From c78206f0fc74bb86b5d71b2d6d741333f698d0a8 Mon Sep 17 00:00:00 2001 From: went tang Date: Fri, 13 Jan 2023 09:48:04 +0800 Subject: [PATCH 1/4] WIP: helm --- .../dapr/.helmignore | 0 .../dapr/Chart.yaml | 0 .../dapr/README.md | 0 .../dapr/charts/dapr_config}/.helmignore | 0 .../dapr/charts/dapr_config/Chart.yaml | 0 .../charts/dapr_config/templates/_helpers.tpl | 0 .../templates/dapr_default_config.yaml | 0 .../dapr/charts/dapr_config/values.yaml | 0 .../dapr/charts/dapr_dashboard}/.helmignore | 0 .../dapr/charts/dapr_dashboard/Chart.yaml | 0 .../dapr_dashboard/templates/_helpers.tpl | 0 .../templates/dapr_dashboard_deployment.yaml | 0 .../dapr_dashboard_poddisruptionbudget.yaml | 0 .../templates/dapr_dashboard_service.yaml | 0 .../dapr/charts/dapr_dashboard/values.yaml | 0 .../dapr/charts/dapr_operator}/.helmignore | 0 .../dapr/charts/dapr_operator/Chart.yaml | 0 .../dapr_operator/templates/_helpers.tpl | 0 .../templates/dapr_operator_deployment.yaml | 0 .../dapr_operator_poddisruptionbudget.yaml | 0 .../templates/dapr_operator_service.yaml | 0 .../dapr/charts/dapr_operator/values.yaml | 0 .../dapr/charts/dapr_placement}/.helmignore | 0 .../dapr/charts/dapr_placement/Chart.yaml | 0 .../dapr_placement/templates/_helpers.tpl | 0 .../templates/dapr_placement_deployment.yaml | 0 .../dapr_placement_poddisruptionbudget.yaml | 0 .../templates/dapr_placement_service.yaml | 0 .../dapr/charts/dapr_placement/values.yaml | 0 .../dapr/charts/dapr_rbac}/.helmignore | 0 .../dapr/charts/dapr_rbac/Chart.yaml | 0 .../templates/ClusterRoleBinding.yaml | 0 .../dapr_rbac/templates/ServiceAccount.yaml | 0 .../charts/dapr_rbac/templates/_helpers.tpl | 0 .../dapr/charts/dapr_rbac/values.yaml | 0 .../dapr/charts/dapr_sentry}/.helmignore | 0 .../dapr/charts/dapr_sentry/Chart.yaml | 0 .../charts/dapr_sentry/templates/_helpers.tpl | 0 .../templates/dapr_sentry_deployment.yaml | 0 .../dapr_sentry_poddisruptionbudget.yaml | 0 .../templates/dapr_sentry_service.yaml | 0 .../dapr/charts/dapr_sentry/values.yaml | 0 .../charts/dapr_sidecar_injector}/.helmignore | 0 .../charts/dapr_sidecar_injector/Chart.yaml | 0 .../dapr_sidecar_injector_deployment.yaml | 0 ..._sidecar_injector_poddisruptionbudget.yaml | 0 .../dapr_sidecar_injector_service.yaml | 0 .../dapr_sidecar_injector_webhook_config.yaml | 0 .../charts/dapr_sidecar_injector/values.yaml | 0 .../dapr/crds/components.yaml | 0 .../dapr/crds/configuration.yaml | 0 .../dapr/crds/resiliency.yaml | 0 .../dapr/crds/subscription.yaml | 0 .../dapr/templates/_helpers.tpl | 0 .../dapr/values.yaml | 0 .../elasticsearch/.helmignore | 0 .../elasticsearch/Chart.lock | 0 .../elasticsearch/Chart.yaml | 0 .../elasticsearch/README.md | 0 .../elasticsearch/charts/common}/.helmignore | 0 .../elasticsearch/charts/common/Chart.yaml | 0 .../elasticsearch/charts/common/README.md | 0 .../charts/common/templates/_affinities.tpl | 0 .../charts/common/templates/_capabilities.tpl | 0 .../charts/common/templates/_errors.tpl | 0 .../charts/common/templates/_images.tpl | 0 .../charts/common/templates/_ingress.tpl | 0 .../charts/common/templates/_labels.tpl | 0 .../charts/common/templates/_names.tpl | 0 .../charts/common/templates/_secrets.tpl | 0 .../charts/common/templates/_storage.tpl | 0 .../charts/common/templates/_tplvalues.tpl | 0 .../charts/common/templates/_utils.tpl | 0 .../charts/common/templates/_warnings.tpl | 0 .../templates/validations/_cassandra.tpl | 0 .../common/templates/validations/_mariadb.tpl | 0 .../common/templates/validations/_mongodb.tpl | 0 .../templates/validations/_postgresql.tpl | 0 .../common/templates/validations/_redis.tpl | 0 .../templates/validations/_validations.tpl | 0 .../elasticsearch/charts/common/values.yaml | 0 .../elasticsearch/charts/kibana/.helmignore | 0 .../elasticsearch/charts/kibana/Chart.lock | 0 .../elasticsearch/charts/kibana/Chart.yaml | 0 .../elasticsearch/charts/kibana/README.md | 0 .../charts/kibana}/charts/common/.helmignore | 0 .../charts/kibana/charts/common/Chart.yaml | 0 .../charts/kibana/charts/common/README.md | 0 .../charts/common/templates/_affinities.tpl | 0 .../charts/common/templates/_capabilities.tpl | 0 .../charts/common/templates/_errors.tpl | 0 .../charts/common/templates/_images.tpl | 0 .../charts/common/templates/_ingress.tpl | 0 .../charts/common/templates/_labels.tpl | 0 .../kibana/charts/common/templates/_names.tpl | 0 .../charts/common/templates/_secrets.tpl | 0 .../charts/common/templates/_storage.tpl | 0 .../charts/common/templates/_tplvalues.tpl | 0 .../kibana/charts/common/templates/_utils.tpl | 0 .../charts/common/templates/_warnings.tpl | 0 .../templates/validations/_cassandra.tpl | 0 .../common/templates/validations/_mariadb.tpl | 0 .../common/templates/validations/_mongodb.tpl | 0 .../templates/validations/_postgresql.tpl | 0 .../common/templates/validations/_redis.tpl | 0 .../templates/validations/_validations.tpl | 0 .../charts/kibana/charts/common/values.yaml | 0 .../charts/kibana/ci/values-with-es.yaml | 0 .../charts/kibana/templates/NOTES.txt | 0 .../charts/kibana/templates/_helpers.tpl | 0 .../charts/kibana/templates/configmap.yaml | 0 .../charts/kibana/templates/deployment.yaml | 0 .../charts/kibana/templates/extra-list.yaml | 0 .../charts/kibana/templates/ingress.yaml | 0 .../kibana/templates/plugins-configmap.yaml | 0 .../charts/kibana/templates/pvc.yaml | 0 .../templates/saved-objects-configmap.yaml | 0 .../charts/kibana/templates/secret.yaml | 0 .../charts/kibana/templates/service.yaml | 0 .../kibana/templates/serviceaccount.yaml | 0 .../kibana/templates/servicemonitor.yaml | 0 .../charts/kibana/templates/tls-secret.yaml | 0 .../elasticsearch/charts/kibana/values.yaml | 0 .../elasticsearch/ci/ct-values.yaml | 0 .../elasticsearch/templates/NOTES.txt | 0 .../elasticsearch/templates/_helpers.tpl | 0 .../templates/configmap-curator.yaml | 0 .../elasticsearch/templates/configmap-es.yaml | 0 .../templates/configmap-initscripts.yaml | 0 .../templates/coordinating-hpa.yaml | 0 .../templates/coordinating-statefulset.yaml | 0 .../templates/coordinating-svc.yaml | 0 .../elasticsearch/templates/cronjob.yaml | 0 .../elasticsearch/templates/data-hpa.yaml | 0 .../templates/data-statefulset.yaml | 0 .../elasticsearch/templates/data-svc.yaml | 0 .../elasticsearch/templates/extra-list.yaml | 0 .../templates/hooks/job.install.yaml | 0 .../templates/ingest-statefulset.yaml | 0 .../elasticsearch/templates/ingest-svc.yaml | 0 .../elasticsearch/templates/ingress.yaml | 0 .../elasticsearch/templates/master-hpa.yaml | 0 .../templates/master-statefulset.yaml | 0 .../elasticsearch/templates/master-svc.yaml | 0 .../templates/metrics-deploy.yaml | 0 .../elasticsearch/templates/metrics-svc.yaml | 0 .../templates/podsecuritypolicy.yaml | 0 .../elasticsearch/templates/role.yaml | 0 .../elasticsearch/templates/rolebinding.yaml | 0 .../elasticsearch/templates/secrets.yaml | 0 .../templates/serviceaccount.yaml | 0 .../templates/servicemonitor.yaml | 0 .../elasticsearch/templates/tls-secret.yaml | 0 .../elasticsearch/values.yaml | 0 .../fluent-bit/Chart.yaml | 0 .../fluent-bit/README.md | 0 .../fluent-bit/templates/_helpers.tpl | 0 .../fluent-bit/templates/cluster-role.yaml | 1 + .../templates/cluster-rolebinding.yaml | 1 + .../fluent-bit/templates/daemonset.yaml | 1 + .../templates/fluent-bit-secret.yaml | 1 + .../fluent-bit/templates/psp.yaml | 1 + .../fluent-bit/templates/secret.yaml | 1 + .../fluent-bit/templates/service.yaml | 1 + .../fluent-bit/templates/serviceaccount.yaml | 1 + .../fluent-bit/templates/servicemonitor.yaml | 2 + .../templates/tests/test-configmap.yaml | 0 .../fluent-bit/templates/tests/test.yaml | 0 .../fluent-bit/values.yaml | 2 +- .../kafka/.helmignore | 0 deployment/charts/kafka/Chart.lock | 9 + deployment/charts/kafka/Chart.yaml | 33 + deployment/charts/kafka/README.md | 1050 +++++++++ .../kafka}/charts/common/.helmignore | 0 .../kafka}/charts/common/Chart.yaml | 12 +- .../kafka}/charts/common/README.md | 85 +- .../charts/common/templates/_affinities.tpl | 22 +- .../charts/common/templates/_capabilities.tpl | 30 +- .../charts/common/templates/_errors.tpl | 0 .../charts/common/templates/_images.tpl | 11 +- .../charts/common/templates/_ingress.tpl | 15 +- .../charts/common/templates/_labels.tpl | 0 .../kafka}/charts/common/templates/_names.tpl | 14 + .../charts/common/templates/_secrets.tpl | 165 ++ .../charts/common/templates/_storage.tpl | 0 .../charts/common/templates/_tplvalues.tpl | 0 .../kafka/charts/common/templates/_utils.tpl | 62 + .../charts/common/templates/_warnings.tpl | 0 .../templates/validations/_cassandra.tpl | 0 .../common/templates/validations/_mariadb.tpl | 0 .../common/templates/validations/_mongodb.tpl | 4 +- .../common/templates/validations/_mysql.tpl | 103 + .../templates/validations/_postgresql.tpl | 0 .../common/templates/validations/_redis.tpl | 4 +- .../templates/validations/_validations.tpl | 0 .../kafka}/charts/common/values.yaml | 0 .../kafka/charts/zookeeper}/.helmignore | 0 .../charts/kafka/charts/zookeeper/Chart.lock | 6 + .../charts/kafka/charts/zookeeper/Chart.yaml | 24 + .../charts/kafka/charts/zookeeper/README.md | 532 +++++ .../zookeeper}/charts/common/.helmignore | 0 .../charts/zookeeper/charts/common/Chart.yaml | 23 + .../charts/zookeeper/charts/common/README.md | 351 +++ .../charts/common/templates/_affinities.tpl | 106 + .../charts/common/templates/_capabilities.tpl | 154 ++ .../charts/common/templates/_errors.tpl | 0 .../charts/common/templates/_images.tpl | 76 + .../charts/common/templates/_ingress.tpl | 68 + .../charts/common/templates/_labels.tpl | 0 .../charts/common/templates/_names.tpl | 70 + .../charts/common/templates/_secrets.tpl | 50 +- .../charts/common/templates/_storage.tpl | 0 .../charts/common/templates/_tplvalues.tpl | 0 .../charts/common/templates/_utils.tpl | 2 +- .../charts/common/templates/_warnings.tpl | 0 .../templates/validations/_cassandra.tpl | 2 +- .../common/templates/validations/_mariadb.tpl | 2 +- .../common/templates/validations/_mongodb.tpl | 108 + .../common/templates/validations/_mysql.tpl | 103 + .../templates/validations/_postgresql.tpl | 4 +- .../common/templates/validations/_redis.tpl | 76 + .../templates/validations/_validations.tpl | 0 .../zookeeper}/charts/common/values.yaml | 0 .../charts/zookeeper/templates/NOTES.txt | 76 + .../charts/zookeeper/templates/_helpers.tpl | 361 +++ .../charts/zookeeper/templates/configmap.yaml | 17 + .../zookeeper}/templates/extra-list.yaml | 0 .../zookeeper/templates/metrics-svc.yaml | 29 + .../zookeeper/templates/networkpolicy.yaml | 41 + .../kafka/charts/zookeeper/templates/pdb.yaml | 26 + .../zookeeper/templates/prometheusrule.yaml} | 23 +- .../templates/scripts-configmap.yaml | 102 + .../charts/zookeeper/templates/secrets.yaml | 77 + .../zookeeper/templates/serviceaccount.yaml | 21 + .../zookeeper/templates/servicemonitor.yaml | 53 + .../zookeeper/templates/statefulset.yaml | 532 +++++ .../zookeeper/templates/svc-headless.yaml | 42 + .../kafka/charts/zookeeper/templates/svc.yaml | 71 + .../zookeeper/templates/tls-secrets.yaml | 55 + .../charts/kafka/charts/zookeeper/values.yaml | 877 +++++++ deployment/charts/kafka/templates/NOTES.txt | 310 +++ .../charts/kafka/templates/_helpers.tpl | 509 ++++ .../kafka/templates/configmap.yaml} | 13 +- .../kafka}/templates/extra-list.yaml | 0 .../charts/kafka/templates/jaas-secret.yaml | 40 + .../charts/kafka/templates/jmx-configmap.yaml | 64 + .../kafka/templates/jmx-metrics-svc.yaml | 34 + .../templates/kafka-metrics-deployment.yaml | 171 ++ .../kafka-metrics-serviceaccount.yaml | 16 + .../kafka/templates/kafka-metrics-svc.yaml | 34 + .../templates/kafka-provisioning-secret.yaml | 19 + .../kafka-provisioning-serviceaccount.yaml | 15 + .../kafka/templates/kafka-provisioning.yaml | 260 +++ .../kafka/templates/log4j-configmap.yaml | 17 + .../kafka/templates/networkpolicy-egress.yaml | 22 + .../templates/networkpolicy-ingress.yaml | 53 + .../kafka/templates/poddisruptionbudget.yaml} | 15 +- .../kafka/templates/prometheusrule.yaml | 20 + deployment/charts/kafka/templates/role.yaml | 24 + .../kafka/templates/rolebinding.yaml} | 17 +- .../kafka/templates/scripts-configmap.yaml | 202 ++ .../kafka/templates/serviceaccount.yaml | 20 + .../templates/servicemonitor-jmx-metrics.yaml | 53 + .../templates/servicemonitor-metrics.yaml | 53 + .../charts/kafka/templates/statefulset.yaml | 610 +++++ .../kafka/templates/svc-external-access.yaml | 63 + .../charts/kafka/templates/svc-headless.yaml | 37 + deployment/charts/kafka/templates/svc.yaml | 63 + .../charts/kafka/templates/tls-secrets.yaml | 30 + deployment/charts/kafka/values.yaml | 1752 ++++++++++++++ .../minio}/.helmignore | 0 .../minio/Chart.yaml | 0 .../minio/README.md | 0 .../minio/ci/distributed-values.yaml | 0 .../minio/templates/NOTES.txt | 0 .../minio/templates/_helper_create_bucket.txt | 0 .../minio/templates/_helpers.tpl | 0 .../minio/templates/configmap.yaml | 0 .../minio/templates/deployment.yaml | 0 .../minio/templates/ingress.yaml | 0 .../minio/templates/networkpolicy.yaml | 0 .../minio/templates/poddisruptionbudget.yaml | 0 .../post-install-create-bucket-job.yaml | 0 .../post-install-prometheus-metrics-job.yaml | 0 .../post-install-prometheus-metrics-role.yaml | 0 ...nstall-prometheus-metrics-rolebinding.yaml | 0 ...all-prometheus-metrics-serviceaccount.yaml | 0 .../minio/templates/pvc.yaml | 0 .../minio/templates/secrets.yaml | 0 .../minio/templates/service.yaml | 0 .../minio/templates/serviceaccount.yaml | 0 .../minio/templates/servicemonitor.yaml | 0 .../minio/templates/statefulset.yaml | 0 .../minio/values.yaml | 0 .../zookeeper => charts/mongodb}/.helmignore | 0 deployment/charts/mongodb/Chart.lock | 6 + deployment/charts/mongodb/Chart.yaml | 30 + deployment/charts/mongodb/README.md | 795 +++++++ .../mongodb}/charts/common/.helmignore | 0 .../charts/mongodb/charts/common/Chart.yaml | 23 + .../charts/mongodb/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/mongodb/charts/common/values.yaml | 5 + deployment/charts/mongodb/templates/NOTES.txt | 202 ++ .../charts/mongodb/templates/_helpers.tpl | 472 ++++ .../mongodb/templates/arbiter/configmap.yaml | 18 + .../templates/arbiter/headless-svc.yaml | 33 + .../charts/mongodb/templates/arbiter/pdb.yaml | 25 + .../templates/arbiter/statefulset.yaml | 298 +++ .../mongodb/templates/common-scripts-cm.yaml | 122 + .../mongodb/templates/configmap.yaml} | 14 +- .../charts/mongodb/templates/extra-list.yaml | 4 + .../mongodb/templates/hidden/configmap.yaml | 15 + .../templates/hidden/external-access-svc.yaml | 70 + .../templates/hidden/headless-svc.yaml | 34 + .../charts/mongodb/templates/hidden/pdb.yaml | 22 + .../mongodb/templates/hidden/statefulset.yaml | 556 +++++ .../templates/initialization-configmap.yaml | 17 + .../mongodb/templates/metrics-svc.yaml} | 27 +- .../mongodb/templates/prometheusrule.yaml | 18 + deployment/charts/mongodb/templates/psp.yaml | 50 + .../replicaset/external-access-svc.yaml | 70 + .../templates/replicaset/headless-svc.yaml | 34 + .../mongodb/templates/replicaset/pdb.yaml | 25 + .../replicaset/scripts-configmap.yaml | 305 +++ .../templates/replicaset/statefulset.yaml | 563 +++++ .../mongodb/templates/replicaset/svc.yaml | 43 + deployment/charts/mongodb/templates/role.yaml | 30 + .../charts/mongodb/templates/rolebinding.yaml | 19 + .../charts/mongodb/templates/secrets-ca.yaml | 35 + .../charts/mongodb/templates/secrets.yaml | 41 + .../mongodb/templates/serviceaccount.yaml | 23 + .../mongodb/templates/servicemonitor.yaml | 48 + .../mongodb/templates/standalone/dep-sts.yaml | 486 ++++ .../mongodb/templates/standalone/pvc.yaml | 33 + .../mongodb/templates/standalone/svc.yaml | 61 + deployment/charts/mongodb/values.schema.json | 173 ++ deployment/charts/mongodb/values.yaml | 2077 +++++++++++++++++ .../mysql}/.helmignore | 0 deployment/charts/mysql/Chart.lock | 6 + deployment/charts/mysql/Chart.yaml | 28 + deployment/charts/mysql/README.md | 554 +++++ .../mysql/charts/common}/.helmignore | 0 .../charts/mysql/charts/common/Chart.yaml | 23 + .../charts/mysql/charts/common/README.md | 351 +++ .../charts/common/templates/_affinities.tpl | 106 + .../charts/common/templates/_capabilities.tpl | 154 ++ .../mysql/charts/common/templates/_errors.tpl | 23 + .../mysql/charts/common/templates/_images.tpl | 76 + .../charts/common/templates/_ingress.tpl | 68 + .../mysql/charts/common/templates/_labels.tpl | 18 + .../mysql/charts/common/templates/_names.tpl | 66 + .../charts/common/templates/_secrets.tpl | 165 ++ .../charts/common/templates/_storage.tpl | 23 + .../charts/common/templates/_tplvalues.tpl | 13 + .../mysql/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/mysql/charts/common/values.yaml | 5 + deployment/charts/mysql/templates/NOTES.txt | 75 + .../charts/mysql/templates/_helpers.tpl | 161 ++ .../charts/mysql/templates/extra-list.yaml | 4 + .../charts/mysql/templates/metrics-svc.yaml | 29 + .../charts/mysql/templates/networkpolicy.yaml | 40 + .../mysql/templates/primary/configmap.yaml | 18 + .../primary/initialization-configmap.yaml | 17 + .../charts/mysql/templates/primary/pdb.yaml | 25 + .../mysql/templates/primary/statefulset.yaml | 382 +++ .../mysql/templates/primary/svc-headless.yaml | 29 + .../charts/mysql/templates/primary/svc.yaml | 52 + .../mysql/templates/prometheusrule.yaml | 22 + deployment/charts/mysql/templates/role.yaml | 24 + .../mysql}/templates/rolebinding.yaml | 21 +- .../mysql/templates/secondary/configmap.yaml | 18 + .../charts/mysql/templates/secondary/pdb.yaml | 25 + .../templates/secondary/statefulset.yaml | 363 +++ .../templates/secondary/svc-headless.yaml | 31 + .../charts/mysql/templates/secondary/svc.yaml | 54 + .../charts/mysql/templates/secrets.yaml | 21 + .../mysql/templates/serviceaccount.yaml | 23 + .../mysql/templates/servicemonitor.yaml | 49 + deployment/charts/mysql/values.schema.json | 195 ++ deployment/charts/mysql/values.yaml | 1208 ++++++++++ .../builder => charts/quanxiang}/.helmignore | 0 deployment/charts/quanxiang/Chart.lock | 99 + deployment/charts/quanxiang/Chart.yaml | 111 + .../quanxiang/charts/appcenter}/.helmignore | 0 .../quanxiang/charts/appcenter/Chart.yaml | 24 + .../charts/appcenter}/templates/_helpers.tpl | 0 .../appcenter}/templates/configmap.yaml | 18 +- .../appcenter}/templates/deployment.yaml | 4 +- .../charts/appcenter}/templates/service.yaml | 2 +- .../templates/tests/test-connection.yaml | 0 .../quanxiang/charts/appcenter/values.yaml | 22 + .../quanxiang/charts}/audit/.helmignore | 0 .../charts/quanxiang/charts/audit/Chart.yaml | 24 + .../charts/audit}/templates/_helpers.tpl | 0 .../charts}/audit/templates/configmap.yaml | 8 +- .../charts}/audit/templates/deployment.yaml | 2 +- .../charts}/audit/templates/service.yaml | 2 +- .../templates/tests/test-connection.yaml | 0 .../charts/quanxiang/charts/audit/values.yaml | 20 + .../quanxiang/charts/builder}/.helmignore | 0 .../quanxiang/charts}/builder/Chart.yaml | 0 .../charts}/builder/templates/_helpers.tpl | 4 + .../builder/templates/pipeline/build.yaml | 1 + .../templates/pipeline/register-api.yaml | 8 +- .../charts/builder/templates/secrets.yaml | 22 + .../builder/templates/serviceaccount.yaml | 11 + .../builder/templates/task/git-clone.yaml | 0 .../builder/templates/task/register-api.yaml | 2 +- .../quanxiang/charts/builder/values.yaml | 19 + .../quanxiang/charts}/dispatcher/.helmignore | 0 .../quanxiang/charts/dispatcher/Chart.yaml | 24 + .../charts}/dispatcher/templates/_helpers.tpl | 0 .../dispatcher/templates/configmap.yaml | 20 +- .../dispatcher/templates/deployment.yaml | 4 +- .../charts}/dispatcher/templates/service.yaml | 2 +- .../templates/tests/test-connection.yaml | 0 .../quanxiang/charts/dispatcher/values.yaml | 34 + .../charts/elasticsearch-17.9.24.tgz | Bin 0 -> 93754 bytes .../quanxiang/charts/entrepot}/.helmignore | 0 .../quanxiang/charts}/entrepot/Chart.yaml | 0 .../charts}/entrepot/templates/_helpers.tpl | 0 .../charts}/entrepot/templates/configmap.yaml | 18 +- .../entrepot/templates/deployment.yaml | 14 +- .../charts}/entrepot/templates/service.yaml | 5 +- .../quanxiang/charts/entrepot/values.yaml | 23 + .../quanxiang/charts/faas}/.helmignore | 0 .../quanxiang/charts}/faas/Chart.yaml | 0 .../charts}/faas/subscribe_faas.yaml | 1 + .../charts}/faas/templates/_helpers.tpl | 0 .../charts}/faas/templates/configmap.yaml | 25 +- .../charts}/faas/templates/deployment.yaml | 8 +- .../charts}/faas/templates/kafka.yaml | 3 +- .../charts}/faas/templates/role.yaml | 0 .../charts}/faas/templates/role_bidding.yaml | 3 +- .../charts}/faas/templates/service.yaml | 2 +- .../faas/templates/serviceaccount.yaml | 2 +- .../faas/templates/tests/test-connection.yaml | 0 .../charts/quanxiang/charts/faas/values.yaml | 20 + .../quanxiang/charts}/fileserver/.helmignore | 0 .../quanxiang/charts/fileserver/Chart.yaml | 24 + .../charts}/fileserver/templates/_helpers.tpl | 0 .../fileserver/templates/configmap.yaml | 22 +- .../fileserver/templates/deployment.yaml | 22 +- .../charts}/fileserver/templates/ingress.yaml | 2 +- .../charts}/fileserver/templates/service.yml | 2 +- .../templates/tests/test-connection.yaml | 0 .../quanxiang/charts/fileserver/values.yaml | 43 + .../quanxiang/charts}/flow/.helmignore | 0 .../quanxiang/charts}/flow/0.6.2.sql | 0 .../charts/quanxiang/charts/flow/Chart.yaml | 24 + .../charts}/flow/templates/_helpers.tpl | 0 .../charts}/flow/templates/configmap.yaml | 20 +- .../charts}/flow/templates/deployment.yaml | 6 +- .../charts}/flow/templates/service.yaml | 2 +- .../flow/templates/subscription-flow.yaml | 2 +- .../flow/templates/tests/test-connection.yaml | 0 .../charts/quanxiang/charts/flow/values.yaml | 22 + .../quanxiang/charts/fluent-bit-2.10.3.tgz | Bin 0 -> 14321 bytes .../quanxiang/charts}/form/.helmignore | 0 .../charts/quanxiang/charts/form/Chart.yaml | 24 + .../charts}/form/templates/_helpers.tpl | 0 .../charts}/form/templates/configmap.yaml | 42 +- .../charts}/form/templates/deployment.yaml | 10 +- .../charts}/form/templates/pub_sub_kafka.yml | 4 +- .../charts}/form/templates/service.yaml | 2 +- .../form/templates/tests/test-connection.yaml | 0 .../charts/quanxiang/charts/form/values.yaml | 37 + .../quanxiang/charts}/goalie/.helmignore | 0 .../charts/quanxiang/charts/goalie/Chart.yaml | 24 + .../charts}/goalie/templates/_helpers.tpl | 0 .../charts}/goalie/templates/configmap.yaml | 20 +- .../charts}/goalie/templates/deployment.yaml | 6 +- .../charts}/goalie/templates/service.yaml | 2 +- .../templates/tests/test-connection.yaml | 0 .../quanxiang/charts/goalie/values.yaml | 18 + .../quanxiang/charts/implant}/.helmignore | 0 .../quanxiang/charts}/implant/Chart.yaml | 0 .../charts}/implant/templates/_helpers.tpl | 0 .../charts}/implant/templates/deployment.yaml | 9 +- .../implant/templates/faas-pubsub.yaml | 2 +- .../charts}/implant/templates/role.yaml | 0 .../implant/templates/role_bidding.yaml | 2 +- .../charts}/implant/templates/service.yaml | 2 +- .../implant/templates/serviceaccount.yaml | 2 +- .../templates/tests/test-connection.yaml | 0 .../quanxiang/charts/implant/values.yaml | 22 + .../charts/quanxiang/charts/kafka-20.0.2.tgz | Bin 0 -> 115196 bytes .../quanxiang/charts}/kms/.helmignore | 0 .../charts/quanxiang/charts/kms/Chart.yaml | 24 + .../charts}/kms/templates/_helpers.tpl | 0 .../charts}/kms/templates/configmap.yaml | 18 +- .../charts}/kms/templates/deployment.yaml | 6 +- .../charts}/kms/templates/service.yml | 0 .../kms/templates/tests/test-connection.yaml | 0 .../charts/quanxiang/charts/kms/values.yaml | 18 + .../quanxiang/charts}/message/.helmignore | 0 .../quanxiang/charts/message/Chart.yaml | 24 + .../charts/message}/templates/_helpers.tpl | 0 .../charts}/message/templates/configmap.yaml | 24 +- .../charts}/message/templates/email.yaml | 20 +- .../charts}/message/templates/kafka.yaml | 4 +- .../charts}/message/templates/letter.yaml | 4 +- .../charts}/message/templates/message.yaml | 8 +- .../message/templates/subscription-email.yaml | 2 +- .../templates/subscription-letter.yaml | 2 +- .../templates/tests/test-connection.yaml | 0 .../quanxiang/charts/message/values.yaml | 28 + .../charts/quanxiang/charts/minio-5.0.33.tgz | Bin 0 -> 19289 bytes .../quanxiang/charts/mongodb-13.6.2.tgz | Bin 0 -> 74455 bytes .../charts/quanxiang/charts/mysql-9.4.6.tgz | Bin 0 -> 45761 bytes .../charts}/organizations/.helmignore | 0 .../quanxiang/charts/organizations/Chart.yaml | 24 + .../organizations/templates/_helpers.tpl | 0 .../organizations/templates/configmap.yaml | 33 +- .../organizations/templates/deployment.yaml | 4 +- .../organizations/templates/service.yaml | 2 +- .../templates/tests/test-connection.yaml | 0 .../charts/organizations/values.yaml | 20 + .../quanxiang/charts}/persona/.helmignore | 0 .../quanxiang/charts/persona/Chart.yaml | 24 + .../charts}/persona/templates/_helpers.tpl | 0 .../charts}/persona/templates/configmap.yaml | 8 +- .../charts}/persona/templates/deployment.yaml | 6 +- .../charts}/persona/templates/service.yaml | 2 +- .../templates/tests/test-connection.yaml | 0 .../quanxiang/charts/persona/values.yaml | 16 + .../quanxiang/charts}/polyapi/.helmignore | 0 .../quanxiang/charts/polyapi/Chart.yaml | 24 + .../charts}/polyapi/templates/_helpers.tpl | 0 .../charts}/polyapi/templates/configmap.yaml | 18 +- .../charts}/polyapi/templates/deployment.yaml | 7 - .../charts}/polyapi/templates/ingress.yaml | 2 +- .../charts}/polyapi/templates/service.yaml | 2 +- .../templates/tests/test-connection.yaml | 0 .../quanxiang/charts/polyapi/values.yaml | 25 + .../quanxiang/charts}/polygate/.helmignore | 0 .../quanxiang/charts/polygate/Chart.yaml | 24 + .../charts}/polygate/templates/_helpers.tpl | 0 .../charts}/polygate/templates/configmap.yaml | 8 +- .../polygate/templates/deployment.yaml | 4 +- .../charts}/polygate/templates/ingress.yaml | 2 +- .../charts}/polygate/templates/service.yaml | 2 +- .../templates/tests/test-connection.yaml | 0 .../quanxiang/charts/polygate/values.yaml | 37 + .../quanxiang/charts}/process/.helmignore | 0 .../quanxiang/charts/process/Chart.yaml | 24 + .../charts}/process/templates/_helpers.tpl | 0 .../charts}/process/templates/configmap.yaml | 18 +- .../charts}/process/templates/deployment.yaml | 4 +- .../charts}/process/templates/service.yaml | 2 +- .../templates/tests/test-connection.yaml | 0 .../quanxiang/charts/process/values.yaml | 22 + .../charts}/qxp-web-home/.helmignore | 0 .../quanxiang/charts/qxp-web-home/Chart.yaml | 24 + .../qxp-web-home}/templates/_helpers.tpl | 0 .../qxp-web-home/templates/configmap.yaml | 22 +- .../qxp-web-home/templates/deployment.yaml | 10 +- .../qxp-web-home/templates/service.yaml | 2 +- .../templates/tests/test-connection.yaml | 0 .../quanxiang/charts/qxp-web-home/values.yaml | 23 + .../charts}/qxp-web-nginx/.helmignore | 0 .../quanxiang/charts/qxp-web-nginx/Chart.yaml | 24 + .../qxp-web-nginx}/templates/_helpers.tpl | 0 .../qxp-web-nginx/templates/deployment.yaml | 4 +- .../qxp-web-nginx/templates/service.yaml | 2 +- .../templates/tests/test-connection.yaml | 0 .../charts/qxp-web-nginx/values.yaml | 17 + .../charts}/qxp-web-portal/.helmignore | 0 .../charts/qxp-web-portal/Chart.yaml | 24 + .../qxp-web-portal}/templates/_helpers.tpl | 0 .../qxp-web-portal/templates/configmap.yaml | 23 +- .../qxp-web-portal/templates/deployment.yaml | 10 +- .../qxp-web-portal/templates/ingress.yml | 19 +- .../qxp-web-portal/templates/service.yaml | 0 .../templates/tests/test-connection.yaml | 0 .../charts/qxp-web-portal/values.yaml | 27 + .../charts}/qxp-web-vendors/.helmignore | 0 .../charts/qxp-web-vendors/Chart.yaml | 24 + .../qxp-web-vendors}/templates/_helpers.tpl | 0 .../qxp-web-vendors/templates/deployment.yaml | 4 +- .../qxp-web-vendors/templates/ingress.yml | 14 +- .../qxp-web-vendors/templates/service.yaml | 2 +- .../templates/tests/test-connection.yaml | 0 .../charts/qxp-web-vendors/values.yaml | 17 + .../quanxiang/charts/redis-cluster-7.1.0.tgz | Bin 0 -> 97445 bytes .../quanxiang/charts}/search/.helmignore | 0 .../charts/quanxiang/charts/search/Chart.yaml | 24 + .../charts}/search/templates/_helpers.tpl | 0 .../charts}/search/templates/config.yaml | 6 +- .../charts}/search/templates/deployment.yaml | 4 +- .../charts}/search/templates/hpa.yaml | 4 +- .../charts}/search/templates/service.yaml | 2 +- .../templates/tests/test-connection.yaml | 0 .../quanxiang/charts/search/values.yaml | 18 + .../quanxiang/charts}/serving/Chart.yaml | 2 +- .../charts}/serving/templates/_helpers.tpl | 4 + .../charts/serving/templates/secret.yaml | 10 + .../serving/templates/serviceaccount.yaml | 10 + .../quanxiang/charts/serving/values.yaml | 16 + .../quanxiang/charts/warden/.helmignore | 23 + .../quanxiang/charts}/warden/Chart.yaml | 0 .../charts}/warden/templates/_helpers.tpl | 0 .../charts}/warden/templates/configmap.yaml | 14 +- .../charts}/warden/templates/deployment.yaml | 4 +- .../charts}/warden/templates/service.yaml | 2 +- .../templates/tests/test-connection.yaml | 0 .../quanxiang/charts/warden/values.yaml | 19 + .../quanxiang/charts}/web-process/.helmignore | 0 .../quanxiang/charts/web-process/Chart.yaml | 24 + .../web-process/templates/_helpers.tpl | 0 .../web-process/templates/deployment.yaml | 12 +- .../charts}/web-process/templates/service.yml | 2 +- .../templates/tests/test-connection.yaml | 0 .../quanxiang/charts/web-process/values.yaml | 13 + .../charts/quanxiang/templates/_helpers.tpl | 62 + deployment/charts/quanxiang/values.yaml | 405 ++++ deployment/charts/redis-cluster/.helmignore | 21 + .../redis-cluster/Chart.lock | 0 .../redis-cluster/Chart.yaml | 0 .../redis-cluster/README.md | 0 .../redis-cluster/charts/common}/.helmignore | 0 .../redis-cluster/charts/common/Chart.yaml | 0 .../redis-cluster/charts/common/README.md | 0 .../charts/common/templates/_affinities.tpl | 0 .../charts/common/templates/_capabilities.tpl | 0 .../charts/common/templates/_errors.tpl | 23 + .../charts/common/templates/_images.tpl | 0 .../charts/common/templates/_ingress.tpl | 0 .../charts/common/templates/_labels.tpl | 18 + .../charts/common/templates/_names.tpl | 0 .../charts/common/templates/_secrets.tpl | 0 .../charts/common/templates/_storage.tpl | 23 + .../charts/common/templates/_tplvalues.tpl | 13 + .../charts/common/templates/_utils.tpl | 0 .../charts/common/templates/_warnings.tpl | 14 + .../templates/validations/_cassandra.tpl | 72 + .../common/templates/validations/_mariadb.tpl | 103 + .../common/templates/validations/_mongodb.tpl | 0 .../templates/validations/_postgresql.tpl | 129 + .../common/templates/validations/_redis.tpl | 0 .../templates/validations/_validations.tpl | 46 + .../redis-cluster/charts/common/values.yaml | 5 + .../img/redis-cluster-topology.png | Bin .../redis-cluster/img/redis-topology.png | Bin .../redis-cluster/templates/NOTES.txt | 0 .../redis-cluster/templates/_helpers.tpl | 0 .../redis-cluster/templates/configmap.yaml | 0 .../redis-cluster/templates/extra-list.yaml | 4 + .../redis-cluster/templates/headless-svc.yaml | 0 .../templates/metrics-prometheus.yaml | 0 .../redis-cluster/templates/metrics-svc.yaml | 0 .../templates/networkpolicy.yaml | 0 .../templates/poddisruptionbudget.yaml | 0 .../templates/prometheusrule.yaml | 0 .../redis-cluster/templates/psp.yaml | 0 .../redis-cluster/templates/redis-role.yaml | 0 .../templates/redis-rolebinding.yaml | 0 .../templates/redis-serviceaccount.yaml | 0 .../templates/redis-statefulset.yaml | 0 .../redis-cluster/templates/redis-svc.yaml | 0 .../templates/scripts-configmap.yaml | 0 .../redis-cluster/templates/secret.yaml | 0 .../svc-cluster-external-access.yaml | 0 .../redis-cluster/templates/tls-secret.yaml | 0 .../templates/update-cluster.yaml | 0 .../redis-cluster/values.yaml | 0 deployment/cmd/InstallApp.go | 104 - deployment/configs/configs.yml | 96 - deployment/deployment/kibana/Chart.yaml | 5 - .../kibana/templates/configmap.yaml | 26 - .../kibana/templates/deployment.yaml | 57 - .../deployment/kibana/templates/service.yaml | 22 - deployment/deployment/kibana/values.yaml | 2 - .../dapr/templates/NOTES.txt | 9 - .../middleware_deployment/kafka/Chart.yaml | 18 - .../middleware_deployment/kafka/README.md | 443 ---- .../kafka/templates/NOTES.txt | 76 - .../kafka/templates/_helpers.tpl | 128 - .../kafka/templates/configmap-config.yaml | 79 - .../kafka/templates/configmap-jmx.yaml | 64 - .../templates/deployment-kafka-exporter.yaml | 45 - .../kafka/templates/job-config.yaml | 29 - .../kafka/templates/podisruptionbudget.yaml | 14 - .../kafka/templates/prometheusrules.yaml | 16 - .../templates/service-brokers-external.yaml | 77 - .../kafka/templates/service-brokers.yaml | 36 - .../kafka/templates/service-headless.yaml | 21 - .../kafka/templates/servicemonitors.yaml | 47 - .../kafka/templates/statefulset.yaml | 272 --- .../test_topic_create_consume_produce.yaml | 25 - .../middleware_deployment/kafka/values.yaml | 512 ---- .../middleware_deployment/mongodb/.helmignore | 1 - .../middleware_deployment/mongodb/Chart.yaml | 20 - .../middleware_deployment/mongodb/README.md | 336 --- .../docker-entrypoint-initdb.d/README.md | 3 - .../mongodb/templates/NOTES.txt | 96 - .../mongodb/templates/_helpers.tpl | 252 -- .../mongodb/templates/configmap.yaml | 14 - .../templates/deployment-standalone.yaml | 304 --- .../mongodb/templates/ingress.yaml | 33 - .../templates/initialization-configmap.yaml | 13 - .../poddisruptionbudget-arbiter-rs.yaml | 27 - .../poddisruptionbudget-secondary-rs.yaml | 27 - .../templates/prometheus-alerting-rule.yaml | 17 - .../templates/prometheus-service-monitor.yaml | 35 - .../mongodb/templates/pvc-standalone.yaml | 20 - .../mongodb/templates/secrets.yaml | 32 - .../templates/statefulset-arbiter-rs.yaml | 187 -- .../templates/statefulset-primary-rs.yaml | 307 --- .../templates/statefulset-secondary-rs.yaml | 281 --- .../mongodb/templates/svc-headless-rs.yaml | 23 - .../mongodb/templates/svc-primary-rs.yaml | 44 - .../mongodb/templates/svc-standalone.yaml | 43 - .../mongodb/values-production.yaml | 506 ---- .../mongodb/values.schema.json | 147 -- .../middleware_deployment/mongodb/values.yaml | 508 ---- .../middleware_deployment/mysql/.helmignore | 2 - .../middleware_deployment/mysql/Chart.yaml | 17 - .../middleware_deployment/mysql/README.md | 255 -- .../mysql/templates/NOTES.txt | 48 - .../mysql/templates/_helpers.tpl | 43 - .../configurationFiles-configmap.yaml | 12 - .../mysql/templates/deployment.yaml | 259 -- .../initializationFiles-configmap.yaml | 12 - .../mysql/templates/pvc.yaml | 29 - .../mysql/templates/secrets.yaml | 51 - .../mysql/templates/serviceaccount.yaml | 11 - .../mysql/templates/servicemonitor.yaml | 26 - .../mysql/templates/svc.yaml | 42 - .../mysql/templates/tests/test-configmap.yaml | 23 - .../mysql/templates/tests/test.yaml | 59 - .../middleware_deployment/mysql/values.yaml | 247 -- .../zookeeper/Chart.yaml | 13 - .../middleware_deployment/zookeeper/README.md | 154 -- .../zookeeper/templates/NOTES.txt | 7 - .../zookeeper/templates/_helpers.tpl | 46 - .../templates/config-jmx-exporter.yaml | 19 - .../zookeeper/templates/config-script.yaml | 110 - .../zookeeper/templates/job-chroots.yaml | 65 - .../templates/poddisruptionbudget.yaml | 17 - .../zookeeper/templates/service-headless.yaml | 28 - .../zookeeper/templates/service.yaml | 41 - .../zookeeper/templates/servicemonitors.yaml | 56 - .../zookeeper/templates/statefulset.yaml | 226 -- .../zookeeper/values.yaml | 300 --- .../nginx-ingress-controller/Chart.lock | 6 - .../nginx-ingress-controller/Chart.yaml | 28 - .../nginx-ingress-controller/README.md | 422 ---- .../ci/ct-values.yaml | 2 - .../ci/values-production-with-psp.yaml | 13 - .../templates/NOTES.txt | 93 - .../templates/_helpers.tpl | 75 - .../templates/addheaders-configmap.yaml | 16 - .../templates/clusterrole.yaml | 83 - .../templates/controller-configmap.yaml | 28 - .../templates/controller-daemonset.yaml | 221 -- .../templates/controller-deployment.yaml | 211 -- .../templates/controller-hpa.yaml | 35 - .../templates/controller-service.yaml | 89 - .../templates/controller-servicemonitor.yaml | 38 - .../templates/default-backend-configmap.yaml | 18 - .../templates/default-backend-deployment.yaml | 104 - .../default-backend-poddisruptionbudget.yaml | 25 - .../templates/default-backend-service.yaml | 30 - .../templates/dh-param-secret.yaml | 16 - .../templates/ingressclass.yaml | 21 - .../templates/podsecuritypolicy.yaml | 50 - .../templates/proxyheaders-configmap.yaml | 21 - .../templates/role.yaml | 94 - .../templates/serviceaccount.yaml | 20 - .../nginx-ingress-controller/values.yaml | 815 ------- deployment/deployment/portalauth/Chart.yaml | 5 - .../deployment/portalauth/templates/job.yaml | 34 - deployment/deployment/portalauth/values.yaml | 6 - .../quanxiang_charts/app-center/Chart.yaml | 5 - .../app-center/templates/NOTES.txt | 21 - .../quanxiang_charts/app-center/values.yaml | 93 - .../quanxiang_charts/audit/Chart.yaml | 5 - .../audit/templates/NOTES.txt | 21 - .../quanxiang_charts/audit/values.yaml | 90 - .../builder/templates/serviceaccount.yaml | 19 - .../quanxiang_charts/builder/values.yaml | 54 - .../quanxiang_charts/dispatcher/Chart.yaml | 5 - .../dispatcher/templates/NOTES.txt | 21 - .../quanxiang_charts/dispatcher/values.yaml | 93 - .../entrepot/templates/NOTES.txt | 22 - .../templates/tests/test-connection.yaml | 15 - .../quanxiang_charts/entrepot/values.yaml | 93 - .../quanxiang_charts/faas/values.yaml | 90 - .../quanxiang_charts/fileserver/Chart.yaml | 5 - .../fileserver/templates/NOTES.txt | 21 - .../quanxiang_charts/fileserver/values.yaml | 93 - .../quanxiang_charts/flow/Chart.yaml | 5 - .../quanxiang_charts/flow/templates/NOTES.txt | 21 - .../quanxiang_charts/flow/values.yaml | 93 - .../fluent-bit/templates/NOTES.txt | 15 - .../quanxiang_charts/form/Chart.yaml | 5 - .../form/pub_sub_redis.yaml_bak | 16 - .../quanxiang_charts/form/templates/NOTES.txt | 21 - .../quanxiang_charts/form/values.yaml | 93 - .../quanxiang_charts/goalie/Chart.yaml | 5 - .../quanxiang_charts/goalie/values.yaml | 88 - .../implant/templates/NOTES.txt | 22 - .../quanxiang_charts/implant/values.yaml | 140 -- .../quanxiang_charts/kms/Chart.yaml | 5 - .../quanxiang_charts/kms/templates/NOTES.txt | 21 - .../quanxiang_charts/kms/values.yaml | 88 - .../quanxiang_charts/message/Chart.yaml | 5 - .../quanxiang_charts/message/values.yaml | 96 - .../quanxiang_charts/organizations/Chart.yaml | 5 - .../organizations/templates/NOTES.txt | 21 - .../organizations/templates/ingress.yaml | 41 - .../organizations/values.yaml | 88 - .../quanxiang_charts/persona/Chart.yaml | 5 - .../persona/templates/NOTES.txt | 21 - .../quanxiang_charts/persona/values.yaml | 97 - .../quanxiang_charts/polyapi/Chart.yaml | 5 - .../quanxiang_charts/polyapi/templates/de.bak | 51 - .../quanxiang_charts/polyapi/values.yaml | 93 - .../quanxiang_charts/polygate/Chart.yaml | 5 - .../polygate/templates/de.bak | 51 - .../quanxiang_charts/polygate/values.yaml | 102 - .../quanxiang_charts/process/Chart.yaml | 5 - .../process/templates/NOTES.txt | 21 - .../quanxiang_charts/process/values.yaml | 93 - .../quanxiang_charts/qxp-web-home/Chart.yaml | 5 - .../qxp-web-home/templates/NOTES.txt | 21 - .../qxp-web-home/templates/ingress.yml | 26 - .../quanxiang_charts/qxp-web-home/values.yaml | 103 - .../quanxiang_charts/qxp-web-nginx/Chart.yaml | 5 - .../qxp-web-nginx/templates/NOTES.txt | 21 - .../qxp-web-nginx/values.yaml | 94 - .../qxp-web-portal/Chart.yaml | 5 - .../qxp-web-portal/templates/NOTES.txt | 21 - .../qxp-web-portal/templates/_helpers.tpl | 56 - .../qxp-web-portal/values.yaml | 100 - .../qxp-web-vendors/Chart.yaml | 5 - .../qxp-web-vendors/templates/NOTES.txt | 21 - .../qxp-web-vendors/templates/_helpers.tpl | 56 - .../qxp-web-vendors/values.yaml | 97 - .../quanxiang_charts/search/Chart.yaml | 5 - .../search/templates/NOTES.txt | 21 - .../quanxiang_charts/search/values.yaml | 92 - .../serving/templates/secret.yaml | 9 - .../serving/templates/serviceaccount.yaml | 18 - .../quanxiang_charts/serving/values.yaml | 88 - .../quanxiang_charts/warden/values.yaml | 93 - .../quanxiang_charts/web-process/Chart.yaml | 5 - .../web-process/templates/NOTES.txt | 21 - .../quanxiang_charts/web-process/values.yaml | 93 - deployment/deployment/schemas/app_center.sql | 100 - deployment/deployment/schemas/application.sql | 42 - deployment/deployment/schemas/dispatcher.sql | 41 - deployment/deployment/schemas/entrepot.sql | 32 - deployment/deployment/schemas/faas.sql | 146 -- deployment/deployment/schemas/fileserver.sql | 90 - deployment/deployment/schemas/flow.sql | 334 --- deployment/deployment/schemas/form.sql | 115 - deployment/deployment/schemas/goalie.sql | 362 --- deployment/deployment/schemas/kms.sql | 62 - deployment/deployment/schemas/message.sql | 92 - .../deployment/schemas/organizations.sql | 210 -- deployment/deployment/schemas/polyapi.sql | 308 --- deployment/deployment/schemas/process.sql | 259 -- deployment/deployment/search_index/Chart.yaml | 5 - .../search_index/templates/_helpers.tpl | 56 - .../search_index/templates/job.yaml | 34 - .../deployment/search_index/values.yaml | 6 - deployment/go.mod | 23 - deployment/go.sum | 1481 ------------ deployment/main.go | 42 - deployment/pkg/configMysql.go | 86 - deployment/pkg/configs.go | 223 -- deployment/pkg/execcmd.go | 58 - deployment/pkg/importImages.go | 89 - deployment/pkg/installFaas.go | 135 -- deployment/pkg/middlerwareInstall.go | 478 ---- deployment/pkg/modifyValues.go | 332 --- deployment/pkg/startInstall.go | 158 -- deployment/pkg/statusCheck.go | 88 - deployment/pkg/testCondition.go | 75 - deployment/pkg/uninstall.go | 114 - .../scripts/init-artery-engine-persona.js | 112 - deployment/scripts/init_nav.js | 78 - 911 files changed, 26810 insertions(+), 20004 deletions(-) rename deployment/{deployment/middleware_deployment => charts}/dapr/.helmignore (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/Chart.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/README.md (100%) rename deployment/{deployment/kibana => charts/dapr/charts/dapr_config}/.helmignore (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_config/Chart.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_config/templates/_helpers.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_config/templates/dapr_default_config.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_config/values.yaml (100%) rename deployment/{deployment/middleware_deployment/dapr/charts/dapr_config => charts/dapr/charts/dapr_dashboard}/.helmignore (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_dashboard/Chart.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_dashboard/templates/_helpers.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_dashboard/templates/dapr_dashboard_deployment.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_dashboard/templates/dapr_dashboard_poddisruptionbudget.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_dashboard/templates/dapr_dashboard_service.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_dashboard/values.yaml (100%) rename deployment/{deployment/middleware_deployment/dapr/charts/dapr_dashboard => charts/dapr/charts/dapr_operator}/.helmignore (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_operator/Chart.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_operator/templates/_helpers.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_operator/templates/dapr_operator_deployment.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_operator/templates/dapr_operator_poddisruptionbudget.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_operator/templates/dapr_operator_service.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_operator/values.yaml (100%) rename deployment/{deployment/middleware_deployment/dapr/charts/dapr_operator => charts/dapr/charts/dapr_placement}/.helmignore (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_placement/Chart.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_placement/templates/_helpers.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_placement/templates/dapr_placement_deployment.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_placement/templates/dapr_placement_poddisruptionbudget.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_placement/templates/dapr_placement_service.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_placement/values.yaml (100%) rename deployment/{deployment/middleware_deployment/dapr/charts/dapr_placement => charts/dapr/charts/dapr_rbac}/.helmignore (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_rbac/Chart.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_rbac/templates/ClusterRoleBinding.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_rbac/templates/ServiceAccount.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_rbac/templates/_helpers.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_rbac/values.yaml (100%) rename deployment/{deployment/middleware_deployment/dapr/charts/dapr_rbac => charts/dapr/charts/dapr_sentry}/.helmignore (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_sentry/Chart.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_sentry/templates/_helpers.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_sentry/templates/dapr_sentry_deployment.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_sentry/templates/dapr_sentry_poddisruptionbudget.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_sentry/templates/dapr_sentry_service.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_sentry/values.yaml (100%) rename deployment/{deployment/middleware_deployment/dapr/charts/dapr_sentry => charts/dapr/charts/dapr_sidecar_injector}/.helmignore (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_sidecar_injector/Chart.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_deployment.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_poddisruptionbudget.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_service.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_webhook_config.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/charts/dapr_sidecar_injector/values.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/crds/components.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/crds/configuration.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/crds/resiliency.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/crds/subscription.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/templates/_helpers.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/dapr/values.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/.helmignore (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/Chart.lock (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/Chart.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/README.md (100%) rename deployment/{deployment/middleware_deployment/dapr/charts/dapr_sidecar_injector => charts/elasticsearch/charts/common}/.helmignore (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/Chart.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/README.md (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/_affinities.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/_capabilities.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/_errors.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/_images.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/_ingress.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/_labels.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/_names.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/_secrets.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/_storage.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/_tplvalues.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/_utils.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/_warnings.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/validations/_cassandra.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/validations/_mariadb.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/validations/_mongodb.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/validations/_postgresql.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/validations/_redis.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/templates/validations/_validations.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/common/values.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/.helmignore (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/Chart.lock (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/Chart.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/README.md (100%) rename deployment/{deployment/middleware_deployment/elasticsearch => charts/elasticsearch/charts/kibana}/charts/common/.helmignore (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/Chart.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/README.md (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/_affinities.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/_capabilities.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/_errors.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/_images.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/_ingress.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/_labels.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/_names.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/_secrets.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/_storage.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/_tplvalues.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/_utils.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/_warnings.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/validations/_cassandra.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/validations/_mariadb.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/validations/_mongodb.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/validations/_postgresql.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/validations/_redis.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/templates/validations/_validations.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/charts/common/values.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/ci/values-with-es.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/templates/NOTES.txt (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/templates/_helpers.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/templates/configmap.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/templates/deployment.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/templates/extra-list.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/templates/ingress.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/templates/plugins-configmap.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/templates/pvc.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/templates/saved-objects-configmap.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/templates/secret.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/templates/service.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/templates/serviceaccount.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/templates/servicemonitor.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/templates/tls-secret.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/charts/kibana/values.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/ci/ct-values.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/NOTES.txt (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/_helpers.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/configmap-curator.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/configmap-es.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/configmap-initscripts.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/coordinating-hpa.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/coordinating-statefulset.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/coordinating-svc.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/cronjob.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/data-hpa.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/data-statefulset.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/data-svc.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/extra-list.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/hooks/job.install.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/ingest-statefulset.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/ingest-svc.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/ingress.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/master-hpa.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/master-statefulset.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/master-svc.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/metrics-deploy.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/metrics-svc.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/podsecuritypolicy.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/role.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/rolebinding.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/secrets.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/serviceaccount.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/servicemonitor.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/templates/tls-secret.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/elasticsearch/values.yaml (100%) rename deployment/{deployment/quanxiang_charts => charts}/fluent-bit/Chart.yaml (100%) rename deployment/{deployment/quanxiang_charts => charts}/fluent-bit/README.md (100%) rename deployment/{deployment/quanxiang_charts => charts}/fluent-bit/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts}/fluent-bit/templates/cluster-role.yaml (94%) rename deployment/{deployment/quanxiang_charts => charts}/fluent-bit/templates/cluster-rolebinding.yaml (94%) rename deployment/{deployment/quanxiang_charts => charts}/fluent-bit/templates/daemonset.yaml (99%) rename deployment/{deployment/quanxiang_charts => charts}/fluent-bit/templates/fluent-bit-secret.yaml (98%) rename deployment/{deployment/quanxiang_charts => charts}/fluent-bit/templates/psp.yaml (97%) rename deployment/{deployment/quanxiang_charts => charts}/fluent-bit/templates/secret.yaml (96%) rename deployment/{deployment/quanxiang_charts => charts}/fluent-bit/templates/service.yaml (95%) rename deployment/{deployment/quanxiang_charts => charts}/fluent-bit/templates/serviceaccount.yaml (92%) rename deployment/{deployment/quanxiang_charts => charts}/fluent-bit/templates/servicemonitor.yaml (96%) rename deployment/{deployment/quanxiang_charts => charts}/fluent-bit/templates/tests/test-configmap.yaml (100%) rename deployment/{deployment/quanxiang_charts => charts}/fluent-bit/templates/tests/test.yaml (100%) rename deployment/{deployment/quanxiang_charts => charts}/fluent-bit/values.yaml (99%) rename deployment/{deployment/middleware_deployment => charts}/kafka/.helmignore (100%) create mode 100644 deployment/charts/kafka/Chart.lock create mode 100644 deployment/charts/kafka/Chart.yaml create mode 100644 deployment/charts/kafka/README.md rename deployment/{deployment/middleware_deployment/elasticsearch/charts/kibana => charts/kafka}/charts/common/.helmignore (100%) rename deployment/{deployment/nginx-ingress-controller => charts/kafka}/charts/common/Chart.yaml (67%) rename deployment/{deployment/nginx-ingress-controller => charts/kafka}/charts/common/README.md (72%) rename deployment/{deployment/nginx-ingress-controller => charts/kafka}/charts/common/templates/_affinities.tpl (83%) rename deployment/{deployment/nginx-ingress-controller => charts/kafka}/charts/common/templates/_capabilities.tpl (83%) rename deployment/{deployment/middleware_deployment/redis-cluster => charts/kafka}/charts/common/templates/_errors.tpl (100%) rename deployment/{deployment/nginx-ingress-controller => charts/kafka}/charts/common/templates/_images.tpl (88%) rename deployment/{deployment/nginx-ingress-controller => charts/kafka}/charts/common/templates/_ingress.tpl (74%) rename deployment/{deployment/middleware_deployment/redis-cluster => charts/kafka}/charts/common/templates/_labels.tpl (100%) rename deployment/{deployment/nginx-ingress-controller => charts/kafka}/charts/common/templates/_names.tpl (78%) create mode 100644 deployment/charts/kafka/charts/common/templates/_secrets.tpl rename deployment/{deployment/middleware_deployment/redis-cluster => charts/kafka}/charts/common/templates/_storage.tpl (100%) rename deployment/{deployment/middleware_deployment/redis-cluster => charts/kafka}/charts/common/templates/_tplvalues.tpl (100%) create mode 100644 deployment/charts/kafka/charts/common/templates/_utils.tpl rename deployment/{deployment/middleware_deployment/redis-cluster => charts/kafka}/charts/common/templates/_warnings.tpl (100%) rename deployment/{deployment/middleware_deployment/redis-cluster => charts/kafka}/charts/common/templates/validations/_cassandra.tpl (100%) rename deployment/{deployment/middleware_deployment/redis-cluster => charts/kafka}/charts/common/templates/validations/_mariadb.tpl (100%) rename deployment/{deployment/nginx-ingress-controller => charts/kafka}/charts/common/templates/validations/_mongodb.tpl (95%) create mode 100644 deployment/charts/kafka/charts/common/templates/validations/_mysql.tpl rename deployment/{deployment/middleware_deployment/redis-cluster => charts/kafka}/charts/common/templates/validations/_postgresql.tpl (100%) rename deployment/{deployment/nginx-ingress-controller => charts/kafka}/charts/common/templates/validations/_redis.tpl (95%) rename deployment/{deployment/middleware_deployment/redis-cluster => charts/kafka}/charts/common/templates/validations/_validations.tpl (100%) rename deployment/{deployment/middleware_deployment/redis-cluster => charts/kafka}/charts/common/values.yaml (100%) rename deployment/{deployment/middleware_deployment/minio => charts/kafka/charts/zookeeper}/.helmignore (100%) create mode 100644 deployment/charts/kafka/charts/zookeeper/Chart.lock create mode 100644 deployment/charts/kafka/charts/zookeeper/Chart.yaml create mode 100644 deployment/charts/kafka/charts/zookeeper/README.md rename deployment/{deployment/middleware_deployment/redis-cluster => charts/kafka/charts/zookeeper}/charts/common/.helmignore (100%) create mode 100644 deployment/charts/kafka/charts/zookeeper/charts/common/Chart.yaml create mode 100644 deployment/charts/kafka/charts/zookeeper/charts/common/README.md create mode 100644 deployment/charts/kafka/charts/zookeeper/charts/common/templates/_affinities.tpl create mode 100644 deployment/charts/kafka/charts/zookeeper/charts/common/templates/_capabilities.tpl rename deployment/{deployment/nginx-ingress-controller => charts/kafka/charts/zookeeper}/charts/common/templates/_errors.tpl (100%) create mode 100644 deployment/charts/kafka/charts/zookeeper/charts/common/templates/_images.tpl create mode 100644 deployment/charts/kafka/charts/zookeeper/charts/common/templates/_ingress.tpl rename deployment/{deployment/nginx-ingress-controller => charts/kafka/charts/zookeeper}/charts/common/templates/_labels.tpl (100%) create mode 100644 deployment/charts/kafka/charts/zookeeper/charts/common/templates/_names.tpl rename deployment/{deployment/nginx-ingress-controller => charts/kafka/charts/zookeeper}/charts/common/templates/_secrets.tpl (67%) rename deployment/{deployment/nginx-ingress-controller => charts/kafka/charts/zookeeper}/charts/common/templates/_storage.tpl (100%) rename deployment/{deployment/nginx-ingress-controller => charts/kafka/charts/zookeeper}/charts/common/templates/_tplvalues.tpl (100%) rename deployment/{deployment/nginx-ingress-controller => charts/kafka/charts/zookeeper}/charts/common/templates/_utils.tpl (98%) rename deployment/{deployment/nginx-ingress-controller => charts/kafka/charts/zookeeper}/charts/common/templates/_warnings.tpl (100%) rename deployment/{deployment/nginx-ingress-controller => charts/kafka/charts/zookeeper}/charts/common/templates/validations/_cassandra.tpl (96%) rename deployment/{deployment/nginx-ingress-controller => charts/kafka/charts/zookeeper}/charts/common/templates/validations/_mariadb.tpl (97%) create mode 100644 deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_mongodb.tpl create mode 100644 deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_mysql.tpl rename deployment/{deployment/nginx-ingress-controller => charts/kafka/charts/zookeeper}/charts/common/templates/validations/_postgresql.tpl (98%) create mode 100644 deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_redis.tpl rename deployment/{deployment/nginx-ingress-controller => charts/kafka/charts/zookeeper}/charts/common/templates/validations/_validations.tpl (100%) rename deployment/{deployment/nginx-ingress-controller => charts/kafka/charts/zookeeper}/charts/common/values.yaml (100%) create mode 100644 deployment/charts/kafka/charts/zookeeper/templates/NOTES.txt create mode 100644 deployment/charts/kafka/charts/zookeeper/templates/_helpers.tpl create mode 100644 deployment/charts/kafka/charts/zookeeper/templates/configmap.yaml rename deployment/{deployment/middleware_deployment/redis-cluster => charts/kafka/charts/zookeeper}/templates/extra-list.yaml (100%) create mode 100644 deployment/charts/kafka/charts/zookeeper/templates/metrics-svc.yaml create mode 100644 deployment/charts/kafka/charts/zookeeper/templates/networkpolicy.yaml create mode 100644 deployment/charts/kafka/charts/zookeeper/templates/pdb.yaml rename deployment/{deployment/nginx-ingress-controller/templates/controller-prometheusrules.yaml => charts/kafka/charts/zookeeper/templates/prometheusrule.yaml} (53%) create mode 100644 deployment/charts/kafka/charts/zookeeper/templates/scripts-configmap.yaml create mode 100644 deployment/charts/kafka/charts/zookeeper/templates/secrets.yaml create mode 100644 deployment/charts/kafka/charts/zookeeper/templates/serviceaccount.yaml create mode 100644 deployment/charts/kafka/charts/zookeeper/templates/servicemonitor.yaml create mode 100644 deployment/charts/kafka/charts/zookeeper/templates/statefulset.yaml create mode 100644 deployment/charts/kafka/charts/zookeeper/templates/svc-headless.yaml create mode 100644 deployment/charts/kafka/charts/zookeeper/templates/svc.yaml create mode 100644 deployment/charts/kafka/charts/zookeeper/templates/tls-secrets.yaml create mode 100644 deployment/charts/kafka/charts/zookeeper/values.yaml create mode 100644 deployment/charts/kafka/templates/NOTES.txt create mode 100644 deployment/charts/kafka/templates/_helpers.tpl rename deployment/{deployment/nginx-ingress-controller/templates/udp-configmap.yaml => charts/kafka/templates/configmap.yaml} (52%) rename deployment/{deployment/nginx-ingress-controller => charts/kafka}/templates/extra-list.yaml (100%) create mode 100644 deployment/charts/kafka/templates/jaas-secret.yaml create mode 100644 deployment/charts/kafka/templates/jmx-configmap.yaml create mode 100644 deployment/charts/kafka/templates/jmx-metrics-svc.yaml create mode 100644 deployment/charts/kafka/templates/kafka-metrics-deployment.yaml create mode 100644 deployment/charts/kafka/templates/kafka-metrics-serviceaccount.yaml create mode 100644 deployment/charts/kafka/templates/kafka-metrics-svc.yaml create mode 100644 deployment/charts/kafka/templates/kafka-provisioning-secret.yaml create mode 100644 deployment/charts/kafka/templates/kafka-provisioning-serviceaccount.yaml create mode 100644 deployment/charts/kafka/templates/kafka-provisioning.yaml create mode 100644 deployment/charts/kafka/templates/log4j-configmap.yaml create mode 100644 deployment/charts/kafka/templates/networkpolicy-egress.yaml create mode 100644 deployment/charts/kafka/templates/networkpolicy-ingress.yaml rename deployment/{deployment/nginx-ingress-controller/templates/controller-poddisruptionbudget.yaml => charts/kafka/templates/poddisruptionbudget.yaml} (55%) create mode 100644 deployment/charts/kafka/templates/prometheusrule.yaml create mode 100644 deployment/charts/kafka/templates/role.yaml rename deployment/{deployment/nginx-ingress-controller/templates/clusterrolebinding.yaml => charts/kafka/templates/rolebinding.yaml} (63%) create mode 100644 deployment/charts/kafka/templates/scripts-configmap.yaml create mode 100644 deployment/charts/kafka/templates/serviceaccount.yaml create mode 100644 deployment/charts/kafka/templates/servicemonitor-jmx-metrics.yaml create mode 100644 deployment/charts/kafka/templates/servicemonitor-metrics.yaml create mode 100644 deployment/charts/kafka/templates/statefulset.yaml create mode 100644 deployment/charts/kafka/templates/svc-external-access.yaml create mode 100644 deployment/charts/kafka/templates/svc-headless.yaml create mode 100644 deployment/charts/kafka/templates/svc.yaml create mode 100644 deployment/charts/kafka/templates/tls-secrets.yaml create mode 100644 deployment/charts/kafka/values.yaml rename deployment/{deployment/middleware_deployment/redis-cluster => charts/minio}/.helmignore (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/Chart.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/README.md (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/ci/distributed-values.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/NOTES.txt (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/_helper_create_bucket.txt (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/_helpers.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/configmap.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/deployment.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/ingress.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/networkpolicy.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/poddisruptionbudget.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/post-install-create-bucket-job.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/post-install-prometheus-metrics-job.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/post-install-prometheus-metrics-role.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/post-install-prometheus-metrics-rolebinding.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/post-install-prometheus-metrics-serviceaccount.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/pvc.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/secrets.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/service.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/serviceaccount.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/servicemonitor.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/templates/statefulset.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/minio/values.yaml (100%) rename deployment/{deployment/middleware_deployment/zookeeper => charts/mongodb}/.helmignore (100%) create mode 100644 deployment/charts/mongodb/Chart.lock create mode 100644 deployment/charts/mongodb/Chart.yaml create mode 100644 deployment/charts/mongodb/README.md rename deployment/{deployment/nginx-ingress-controller => charts/mongodb}/charts/common/.helmignore (100%) create mode 100644 deployment/charts/mongodb/charts/common/Chart.yaml create mode 100644 deployment/charts/mongodb/charts/common/README.md create mode 100644 deployment/charts/mongodb/charts/common/templates/_affinities.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/_capabilities.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/_errors.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/_images.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/_ingress.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/_labels.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/_names.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/_secrets.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/_storage.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/_tplvalues.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/_utils.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/_warnings.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/validations/_cassandra.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/validations/_mariadb.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/validations/_mongodb.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/validations/_mysql.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/validations/_postgresql.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/validations/_redis.tpl create mode 100644 deployment/charts/mongodb/charts/common/templates/validations/_validations.tpl create mode 100644 deployment/charts/mongodb/charts/common/values.yaml create mode 100644 deployment/charts/mongodb/templates/NOTES.txt create mode 100644 deployment/charts/mongodb/templates/_helpers.tpl create mode 100644 deployment/charts/mongodb/templates/arbiter/configmap.yaml create mode 100644 deployment/charts/mongodb/templates/arbiter/headless-svc.yaml create mode 100644 deployment/charts/mongodb/templates/arbiter/pdb.yaml create mode 100644 deployment/charts/mongodb/templates/arbiter/statefulset.yaml create mode 100644 deployment/charts/mongodb/templates/common-scripts-cm.yaml rename deployment/{deployment/nginx-ingress-controller/templates/tcp-configmap.yaml => charts/mongodb/templates/configmap.yaml} (52%) create mode 100644 deployment/charts/mongodb/templates/extra-list.yaml create mode 100644 deployment/charts/mongodb/templates/hidden/configmap.yaml create mode 100644 deployment/charts/mongodb/templates/hidden/external-access-svc.yaml create mode 100644 deployment/charts/mongodb/templates/hidden/headless-svc.yaml create mode 100644 deployment/charts/mongodb/templates/hidden/pdb.yaml create mode 100644 deployment/charts/mongodb/templates/hidden/statefulset.yaml create mode 100644 deployment/charts/mongodb/templates/initialization-configmap.yaml rename deployment/{deployment/nginx-ingress-controller/templates/controller-metrics-service.yaml => charts/mongodb/templates/metrics-svc.yaml} (53%) create mode 100644 deployment/charts/mongodb/templates/prometheusrule.yaml create mode 100644 deployment/charts/mongodb/templates/psp.yaml create mode 100644 deployment/charts/mongodb/templates/replicaset/external-access-svc.yaml create mode 100644 deployment/charts/mongodb/templates/replicaset/headless-svc.yaml create mode 100644 deployment/charts/mongodb/templates/replicaset/pdb.yaml create mode 100644 deployment/charts/mongodb/templates/replicaset/scripts-configmap.yaml create mode 100644 deployment/charts/mongodb/templates/replicaset/statefulset.yaml create mode 100644 deployment/charts/mongodb/templates/replicaset/svc.yaml create mode 100644 deployment/charts/mongodb/templates/role.yaml create mode 100644 deployment/charts/mongodb/templates/rolebinding.yaml create mode 100644 deployment/charts/mongodb/templates/secrets-ca.yaml create mode 100644 deployment/charts/mongodb/templates/secrets.yaml create mode 100644 deployment/charts/mongodb/templates/serviceaccount.yaml create mode 100644 deployment/charts/mongodb/templates/servicemonitor.yaml create mode 100644 deployment/charts/mongodb/templates/standalone/dep-sts.yaml create mode 100644 deployment/charts/mongodb/templates/standalone/pvc.yaml create mode 100644 deployment/charts/mongodb/templates/standalone/svc.yaml create mode 100644 deployment/charts/mongodb/values.schema.json create mode 100644 deployment/charts/mongodb/values.yaml rename deployment/{deployment/nginx-ingress-controller => charts/mysql}/.helmignore (100%) create mode 100644 deployment/charts/mysql/Chart.lock create mode 100644 deployment/charts/mysql/Chart.yaml create mode 100644 deployment/charts/mysql/README.md rename deployment/{deployment/portalauth => charts/mysql/charts/common}/.helmignore (100%) create mode 100644 deployment/charts/mysql/charts/common/Chart.yaml create mode 100644 deployment/charts/mysql/charts/common/README.md create mode 100644 deployment/charts/mysql/charts/common/templates/_affinities.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/_capabilities.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/_errors.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/_images.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/_ingress.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/_labels.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/_names.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/_secrets.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/_storage.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/_tplvalues.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/_utils.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/_warnings.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/validations/_cassandra.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/validations/_mariadb.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/validations/_mongodb.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/validations/_mysql.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/validations/_postgresql.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/validations/_redis.tpl create mode 100644 deployment/charts/mysql/charts/common/templates/validations/_validations.tpl create mode 100644 deployment/charts/mysql/charts/common/values.yaml create mode 100644 deployment/charts/mysql/templates/NOTES.txt create mode 100644 deployment/charts/mysql/templates/_helpers.tpl create mode 100644 deployment/charts/mysql/templates/extra-list.yaml create mode 100644 deployment/charts/mysql/templates/metrics-svc.yaml create mode 100644 deployment/charts/mysql/templates/networkpolicy.yaml create mode 100644 deployment/charts/mysql/templates/primary/configmap.yaml create mode 100644 deployment/charts/mysql/templates/primary/initialization-configmap.yaml create mode 100644 deployment/charts/mysql/templates/primary/pdb.yaml create mode 100644 deployment/charts/mysql/templates/primary/statefulset.yaml create mode 100644 deployment/charts/mysql/templates/primary/svc-headless.yaml create mode 100644 deployment/charts/mysql/templates/primary/svc.yaml create mode 100644 deployment/charts/mysql/templates/prometheusrule.yaml create mode 100644 deployment/charts/mysql/templates/role.yaml rename deployment/{deployment/nginx-ingress-controller => charts/mysql}/templates/rolebinding.yaml (53%) create mode 100644 deployment/charts/mysql/templates/secondary/configmap.yaml create mode 100644 deployment/charts/mysql/templates/secondary/pdb.yaml create mode 100644 deployment/charts/mysql/templates/secondary/statefulset.yaml create mode 100644 deployment/charts/mysql/templates/secondary/svc-headless.yaml create mode 100644 deployment/charts/mysql/templates/secondary/svc.yaml create mode 100644 deployment/charts/mysql/templates/secrets.yaml create mode 100644 deployment/charts/mysql/templates/serviceaccount.yaml create mode 100644 deployment/charts/mysql/templates/servicemonitor.yaml create mode 100644 deployment/charts/mysql/values.schema.json create mode 100644 deployment/charts/mysql/values.yaml rename deployment/{deployment/quanxiang_charts/builder => charts/quanxiang}/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/Chart.lock create mode 100644 deployment/charts/quanxiang/Chart.yaml rename deployment/{deployment/quanxiang_charts/app-center => charts/quanxiang/charts/appcenter}/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/appcenter/Chart.yaml rename deployment/{deployment/quanxiang_charts/app-center => charts/quanxiang/charts/appcenter}/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts/app-center => charts/quanxiang/charts/appcenter}/templates/configmap.yaml (80%) rename deployment/{deployment/quanxiang_charts/app-center => charts/quanxiang/charts/appcenter}/templates/deployment.yaml (95%) rename deployment/{deployment/quanxiang_charts/app-center => charts/quanxiang/charts/appcenter}/templates/service.yaml (94%) rename deployment/{deployment/quanxiang_charts/app-center => charts/quanxiang/charts/appcenter}/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/appcenter/values.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/audit/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/audit/Chart.yaml rename deployment/{deployment/kibana => charts/quanxiang/charts/audit}/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/audit/templates/configmap.yaml (86%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/audit/templates/deployment.yaml (94%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/audit/templates/service.yaml (93%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/audit/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/audit/values.yaml rename deployment/{deployment/quanxiang_charts/entrepot => charts/quanxiang/charts/builder}/.helmignore (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/builder/Chart.yaml (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/builder/templates/_helpers.tpl (89%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/builder/templates/pipeline/build.yaml (98%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/builder/templates/pipeline/register-api.yaml (80%) create mode 100644 deployment/charts/quanxiang/charts/builder/templates/secrets.yaml create mode 100644 deployment/charts/quanxiang/charts/builder/templates/serviceaccount.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/builder/templates/task/git-clone.yaml (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/builder/templates/task/register-api.yaml (99%) create mode 100644 deployment/charts/quanxiang/charts/builder/values.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/dispatcher/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/dispatcher/Chart.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/dispatcher/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/dispatcher/templates/configmap.yaml (70%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/dispatcher/templates/deployment.yaml (93%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/dispatcher/templates/service.yaml (94%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/dispatcher/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/dispatcher/values.yaml create mode 100644 deployment/charts/quanxiang/charts/elasticsearch-17.9.24.tgz rename deployment/{deployment/quanxiang_charts/faas => charts/quanxiang/charts/entrepot}/.helmignore (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/entrepot/Chart.yaml (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/entrepot/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/entrepot/templates/configmap.yaml (76%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/entrepot/templates/deployment.yaml (84%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/entrepot/templates/service.yaml (69%) create mode 100644 deployment/charts/quanxiang/charts/entrepot/values.yaml rename deployment/{deployment/quanxiang_charts/implant => charts/quanxiang/charts/faas}/.helmignore (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/faas/Chart.yaml (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/faas/subscribe_faas.yaml (80%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/faas/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/faas/templates/configmap.yaml (86%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/faas/templates/deployment.yaml (91%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/faas/templates/kafka.yaml (81%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/faas/templates/role.yaml (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/faas/templates/role_bidding.yaml (75%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/faas/templates/service.yaml (90%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/faas/templates/serviceaccount.yaml (77%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/faas/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/faas/values.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/fileserver/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/fileserver/Chart.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/fileserver/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/fileserver/templates/configmap.yaml (71%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/fileserver/templates/deployment.yaml (75%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/fileserver/templates/ingress.yaml (94%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/fileserver/templates/service.yml (94%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/fileserver/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/fileserver/values.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/flow/.helmignore (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/flow/0.6.2.sql (100%) create mode 100644 deployment/charts/quanxiang/charts/flow/Chart.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/flow/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/flow/templates/configmap.yaml (78%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/flow/templates/deployment.yaml (92%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/flow/templates/service.yaml (95%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/flow/templates/subscription-flow.yaml (80%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/flow/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/flow/values.yaml create mode 100644 deployment/charts/quanxiang/charts/fluent-bit-2.10.3.tgz rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/form/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/form/Chart.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/form/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/form/templates/configmap.yaml (67%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/form/templates/deployment.yaml (92%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/form/templates/pub_sub_kafka.yml (81%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/form/templates/service.yaml (94%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/form/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/form/values.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/goalie/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/goalie/Chart.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/goalie/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/goalie/templates/configmap.yaml (63%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/goalie/templates/deployment.yaml (92%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/goalie/templates/service.yaml (94%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/goalie/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/goalie/values.yaml rename deployment/{deployment/quanxiang_charts/warden => charts/quanxiang/charts/implant}/.helmignore (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/implant/Chart.yaml (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/implant/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/implant/templates/deployment.yaml (83%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/implant/templates/faas-pubsub.yaml (82%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/implant/templates/role.yaml (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/implant/templates/role_bidding.yaml (85%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/implant/templates/service.yaml (94%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/implant/templates/serviceaccount.yaml (73%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/implant/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/implant/values.yaml create mode 100644 deployment/charts/quanxiang/charts/kafka-20.0.2.tgz rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/kms/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/kms/Chart.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/kms/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/kms/templates/configmap.yaml (71%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/kms/templates/deployment.yaml (92%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/kms/templates/service.yml (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/kms/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/kms/values.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/message/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/message/Chart.yaml rename deployment/{deployment/portalauth => charts/quanxiang/charts/message}/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/message/templates/configmap.yaml (72%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/message/templates/email.yaml (75%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/message/templates/kafka.yaml (80%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/message/templates/letter.yaml (93%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/message/templates/message.yaml (90%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/message/templates/subscription-email.yaml (82%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/message/templates/subscription-letter.yaml (82%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/message/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/message/values.yaml create mode 100644 deployment/charts/quanxiang/charts/minio-5.0.33.tgz create mode 100644 deployment/charts/quanxiang/charts/mongodb-13.6.2.tgz create mode 100644 deployment/charts/quanxiang/charts/mysql-9.4.6.tgz rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/organizations/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/organizations/Chart.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/organizations/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/organizations/templates/configmap.yaml (74%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/organizations/templates/deployment.yaml (93%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/organizations/templates/service.yaml (94%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/organizations/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/organizations/values.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/persona/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/persona/Chart.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/persona/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/persona/templates/configmap.yaml (83%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/persona/templates/deployment.yaml (92%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/persona/templates/service.yaml (93%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/persona/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/persona/values.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/polyapi/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/polyapi/Chart.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/polyapi/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/polyapi/templates/configmap.yaml (84%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/polyapi/templates/deployment.yaml (92%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/polyapi/templates/ingress.yaml (93%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/polyapi/templates/service.yaml (95%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/polyapi/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/polyapi/values.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/polygate/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/polygate/Chart.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/polygate/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/polygate/templates/configmap.yaml (92%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/polygate/templates/deployment.yaml (93%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/polygate/templates/ingress.yaml (93%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/polygate/templates/service.yaml (94%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/polygate/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/polygate/values.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/process/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/process/Chart.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/process/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/process/templates/configmap.yaml (70%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/process/templates/deployment.yaml (93%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/process/templates/service.yaml (94%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/process/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/process/values.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-home/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/qxp-web-home/Chart.yaml rename deployment/{deployment/quanxiang_charts/audit => charts/quanxiang/charts/qxp-web-home}/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-home/templates/configmap.yaml (59%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-home/templates/deployment.yaml (86%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-home/templates/service.yaml (93%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-home/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/qxp-web-home/values.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-nginx/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/qxp-web-nginx/Chart.yaml rename deployment/{deployment/quanxiang_charts/message => charts/quanxiang/charts/qxp-web-nginx}/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-nginx/templates/deployment.yaml (92%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-nginx/templates/service.yaml (93%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-nginx/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/qxp-web-nginx/values.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-portal/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/qxp-web-portal/Chart.yaml rename deployment/{deployment/quanxiang_charts/qxp-web-home => charts/quanxiang/charts/qxp-web-portal}/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-portal/templates/configmap.yaml (59%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-portal/templates/deployment.yaml (86%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-portal/templates/ingress.yml (55%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-portal/templates/service.yaml (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-portal/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/qxp-web-portal/values.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-vendors/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/qxp-web-vendors/Chart.yaml rename deployment/{deployment/quanxiang_charts/qxp-web-nginx => charts/quanxiang/charts/qxp-web-vendors}/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-vendors/templates/deployment.yaml (93%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-vendors/templates/ingress.yml (57%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-vendors/templates/service.yaml (93%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/qxp-web-vendors/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/qxp-web-vendors/values.yaml create mode 100644 deployment/charts/quanxiang/charts/redis-cluster-7.1.0.tgz rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/search/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/search/Chart.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/search/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/search/templates/config.yaml (58%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/search/templates/deployment.yaml (93%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/search/templates/hpa.yaml (80%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/search/templates/service.yaml (94%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/search/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/search/values.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/serving/Chart.yaml (98%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/serving/templates/_helpers.tpl (89%) create mode 100644 deployment/charts/quanxiang/charts/serving/templates/secret.yaml create mode 100644 deployment/charts/quanxiang/charts/serving/templates/serviceaccount.yaml create mode 100644 deployment/charts/quanxiang/charts/serving/values.yaml create mode 100644 deployment/charts/quanxiang/charts/warden/.helmignore rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/warden/Chart.yaml (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/warden/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/warden/templates/configmap.yaml (83%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/warden/templates/deployment.yaml (93%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/warden/templates/service.yaml (94%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/warden/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/warden/values.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/web-process/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/web-process/Chart.yaml rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/web-process/templates/_helpers.tpl (100%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/web-process/templates/deployment.yaml (85%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/web-process/templates/service.yml (94%) rename deployment/{deployment/quanxiang_charts => charts/quanxiang/charts}/web-process/templates/tests/test-connection.yaml (100%) create mode 100644 deployment/charts/quanxiang/charts/web-process/values.yaml create mode 100644 deployment/charts/quanxiang/templates/_helpers.tpl create mode 100644 deployment/charts/quanxiang/values.yaml create mode 100644 deployment/charts/redis-cluster/.helmignore rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/Chart.lock (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/Chart.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/README.md (100%) rename deployment/{deployment/search_index => charts/redis-cluster/charts/common}/.helmignore (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/charts/common/Chart.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/charts/common/README.md (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/charts/common/templates/_affinities.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/charts/common/templates/_capabilities.tpl (100%) create mode 100644 deployment/charts/redis-cluster/charts/common/templates/_errors.tpl rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/charts/common/templates/_images.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/charts/common/templates/_ingress.tpl (100%) create mode 100644 deployment/charts/redis-cluster/charts/common/templates/_labels.tpl rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/charts/common/templates/_names.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/charts/common/templates/_secrets.tpl (100%) create mode 100644 deployment/charts/redis-cluster/charts/common/templates/_storage.tpl create mode 100644 deployment/charts/redis-cluster/charts/common/templates/_tplvalues.tpl rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/charts/common/templates/_utils.tpl (100%) create mode 100644 deployment/charts/redis-cluster/charts/common/templates/_warnings.tpl create mode 100644 deployment/charts/redis-cluster/charts/common/templates/validations/_cassandra.tpl create mode 100644 deployment/charts/redis-cluster/charts/common/templates/validations/_mariadb.tpl rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/charts/common/templates/validations/_mongodb.tpl (100%) create mode 100644 deployment/charts/redis-cluster/charts/common/templates/validations/_postgresql.tpl rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/charts/common/templates/validations/_redis.tpl (100%) create mode 100644 deployment/charts/redis-cluster/charts/common/templates/validations/_validations.tpl create mode 100644 deployment/charts/redis-cluster/charts/common/values.yaml rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/img/redis-cluster-topology.png (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/img/redis-topology.png (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/NOTES.txt (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/_helpers.tpl (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/configmap.yaml (100%) create mode 100644 deployment/charts/redis-cluster/templates/extra-list.yaml rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/headless-svc.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/metrics-prometheus.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/metrics-svc.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/networkpolicy.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/poddisruptionbudget.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/prometheusrule.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/psp.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/redis-role.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/redis-rolebinding.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/redis-serviceaccount.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/redis-statefulset.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/redis-svc.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/scripts-configmap.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/secret.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/svc-cluster-external-access.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/tls-secret.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/templates/update-cluster.yaml (100%) rename deployment/{deployment/middleware_deployment => charts}/redis-cluster/values.yaml (100%) delete mode 100644 deployment/cmd/InstallApp.go delete mode 100644 deployment/configs/configs.yml delete mode 100644 deployment/deployment/kibana/Chart.yaml delete mode 100644 deployment/deployment/kibana/templates/configmap.yaml delete mode 100644 deployment/deployment/kibana/templates/deployment.yaml delete mode 100644 deployment/deployment/kibana/templates/service.yaml delete mode 100644 deployment/deployment/kibana/values.yaml delete mode 100644 deployment/deployment/middleware_deployment/dapr/templates/NOTES.txt delete mode 100755 deployment/deployment/middleware_deployment/kafka/Chart.yaml delete mode 100644 deployment/deployment/middleware_deployment/kafka/README.md delete mode 100644 deployment/deployment/middleware_deployment/kafka/templates/NOTES.txt delete mode 100644 deployment/deployment/middleware_deployment/kafka/templates/_helpers.tpl delete mode 100644 deployment/deployment/middleware_deployment/kafka/templates/configmap-config.yaml delete mode 100644 deployment/deployment/middleware_deployment/kafka/templates/configmap-jmx.yaml delete mode 100644 deployment/deployment/middleware_deployment/kafka/templates/deployment-kafka-exporter.yaml delete mode 100644 deployment/deployment/middleware_deployment/kafka/templates/job-config.yaml delete mode 100644 deployment/deployment/middleware_deployment/kafka/templates/podisruptionbudget.yaml delete mode 100644 deployment/deployment/middleware_deployment/kafka/templates/prometheusrules.yaml delete mode 100644 deployment/deployment/middleware_deployment/kafka/templates/service-brokers-external.yaml delete mode 100644 deployment/deployment/middleware_deployment/kafka/templates/service-brokers.yaml delete mode 100644 deployment/deployment/middleware_deployment/kafka/templates/service-headless.yaml delete mode 100644 deployment/deployment/middleware_deployment/kafka/templates/servicemonitors.yaml delete mode 100644 deployment/deployment/middleware_deployment/kafka/templates/statefulset.yaml delete mode 100644 deployment/deployment/middleware_deployment/kafka/templates/tests/test_topic_create_consume_produce.yaml delete mode 100644 deployment/deployment/middleware_deployment/kafka/values.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/.helmignore delete mode 100644 deployment/deployment/middleware_deployment/mongodb/Chart.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/README.md delete mode 100644 deployment/deployment/middleware_deployment/mongodb/files/docker-entrypoint-initdb.d/README.md delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/NOTES.txt delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/_helpers.tpl delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/configmap.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/deployment-standalone.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/ingress.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/initialization-configmap.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/poddisruptionbudget-arbiter-rs.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/poddisruptionbudget-secondary-rs.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/prometheus-alerting-rule.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/prometheus-service-monitor.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/pvc-standalone.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/secrets.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/statefulset-arbiter-rs.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/statefulset-primary-rs.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/statefulset-secondary-rs.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/svc-headless-rs.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/svc-primary-rs.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/templates/svc-standalone.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/values-production.yaml delete mode 100644 deployment/deployment/middleware_deployment/mongodb/values.schema.json delete mode 100644 deployment/deployment/middleware_deployment/mongodb/values.yaml delete mode 100644 deployment/deployment/middleware_deployment/mysql/.helmignore delete mode 100755 deployment/deployment/middleware_deployment/mysql/Chart.yaml delete mode 100755 deployment/deployment/middleware_deployment/mysql/README.md delete mode 100644 deployment/deployment/middleware_deployment/mysql/templates/NOTES.txt delete mode 100644 deployment/deployment/middleware_deployment/mysql/templates/_helpers.tpl delete mode 100644 deployment/deployment/middleware_deployment/mysql/templates/configurationFiles-configmap.yaml delete mode 100644 deployment/deployment/middleware_deployment/mysql/templates/deployment.yaml delete mode 100644 deployment/deployment/middleware_deployment/mysql/templates/initializationFiles-configmap.yaml delete mode 100644 deployment/deployment/middleware_deployment/mysql/templates/pvc.yaml delete mode 100755 deployment/deployment/middleware_deployment/mysql/templates/secrets.yaml delete mode 100644 deployment/deployment/middleware_deployment/mysql/templates/serviceaccount.yaml delete mode 100644 deployment/deployment/middleware_deployment/mysql/templates/servicemonitor.yaml delete mode 100644 deployment/deployment/middleware_deployment/mysql/templates/svc.yaml delete mode 100644 deployment/deployment/middleware_deployment/mysql/templates/tests/test-configmap.yaml delete mode 100644 deployment/deployment/middleware_deployment/mysql/templates/tests/test.yaml delete mode 100644 deployment/deployment/middleware_deployment/mysql/values.yaml delete mode 100644 deployment/deployment/middleware_deployment/zookeeper/Chart.yaml delete mode 100644 deployment/deployment/middleware_deployment/zookeeper/README.md delete mode 100644 deployment/deployment/middleware_deployment/zookeeper/templates/NOTES.txt delete mode 100644 deployment/deployment/middleware_deployment/zookeeper/templates/_helpers.tpl delete mode 100644 deployment/deployment/middleware_deployment/zookeeper/templates/config-jmx-exporter.yaml delete mode 100644 deployment/deployment/middleware_deployment/zookeeper/templates/config-script.yaml delete mode 100644 deployment/deployment/middleware_deployment/zookeeper/templates/job-chroots.yaml delete mode 100644 deployment/deployment/middleware_deployment/zookeeper/templates/poddisruptionbudget.yaml delete mode 100644 deployment/deployment/middleware_deployment/zookeeper/templates/service-headless.yaml delete mode 100644 deployment/deployment/middleware_deployment/zookeeper/templates/service.yaml delete mode 100644 deployment/deployment/middleware_deployment/zookeeper/templates/servicemonitors.yaml delete mode 100644 deployment/deployment/middleware_deployment/zookeeper/templates/statefulset.yaml delete mode 100644 deployment/deployment/middleware_deployment/zookeeper/values.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/Chart.lock delete mode 100644 deployment/deployment/nginx-ingress-controller/Chart.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/README.md delete mode 100644 deployment/deployment/nginx-ingress-controller/ci/ct-values.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/ci/values-production-with-psp.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/NOTES.txt delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/_helpers.tpl delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/addheaders-configmap.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/clusterrole.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/controller-configmap.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/controller-daemonset.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/controller-deployment.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/controller-hpa.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/controller-service.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/controller-servicemonitor.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/default-backend-configmap.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/default-backend-deployment.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/default-backend-poddisruptionbudget.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/default-backend-service.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/dh-param-secret.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/ingressclass.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/podsecuritypolicy.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/proxyheaders-configmap.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/role.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/templates/serviceaccount.yaml delete mode 100644 deployment/deployment/nginx-ingress-controller/values.yaml delete mode 100644 deployment/deployment/portalauth/Chart.yaml delete mode 100644 deployment/deployment/portalauth/templates/job.yaml delete mode 100644 deployment/deployment/portalauth/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/app-center/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/app-center/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/app-center/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/audit/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/audit/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/audit/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/builder/templates/serviceaccount.yaml delete mode 100644 deployment/deployment/quanxiang_charts/builder/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/dispatcher/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/dispatcher/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/dispatcher/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/entrepot/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/entrepot/templates/tests/test-connection.yaml delete mode 100644 deployment/deployment/quanxiang_charts/entrepot/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/faas/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/fileserver/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/fileserver/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/fileserver/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/flow/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/flow/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/flow/values.yaml delete mode 100755 deployment/deployment/quanxiang_charts/fluent-bit/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/form/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/form/pub_sub_redis.yaml_bak delete mode 100644 deployment/deployment/quanxiang_charts/form/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/form/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/goalie/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/goalie/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/implant/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/implant/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/kms/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/kms/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/kms/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/message/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/message/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/organizations/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/organizations/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/organizations/templates/ingress.yaml delete mode 100644 deployment/deployment/quanxiang_charts/organizations/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/persona/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/persona/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/persona/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/polyapi/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/polyapi/templates/de.bak delete mode 100644 deployment/deployment/quanxiang_charts/polyapi/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/polygate/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/polygate/templates/de.bak delete mode 100644 deployment/deployment/quanxiang_charts/polygate/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/process/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/process/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/process/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/qxp-web-home/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/qxp-web-home/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/qxp-web-home/templates/ingress.yml delete mode 100644 deployment/deployment/quanxiang_charts/qxp-web-home/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/qxp-web-nginx/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/qxp-web-nginx/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/qxp-web-nginx/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/qxp-web-portal/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/qxp-web-portal/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/qxp-web-portal/templates/_helpers.tpl delete mode 100644 deployment/deployment/quanxiang_charts/qxp-web-portal/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/qxp-web-vendors/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/_helpers.tpl delete mode 100644 deployment/deployment/quanxiang_charts/qxp-web-vendors/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/search/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/search/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/search/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/serving/templates/secret.yaml delete mode 100644 deployment/deployment/quanxiang_charts/serving/templates/serviceaccount.yaml delete mode 100644 deployment/deployment/quanxiang_charts/serving/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/warden/values.yaml delete mode 100644 deployment/deployment/quanxiang_charts/web-process/Chart.yaml delete mode 100644 deployment/deployment/quanxiang_charts/web-process/templates/NOTES.txt delete mode 100644 deployment/deployment/quanxiang_charts/web-process/values.yaml delete mode 100644 deployment/deployment/schemas/app_center.sql delete mode 100644 deployment/deployment/schemas/application.sql delete mode 100644 deployment/deployment/schemas/dispatcher.sql delete mode 100644 deployment/deployment/schemas/entrepot.sql delete mode 100644 deployment/deployment/schemas/faas.sql delete mode 100644 deployment/deployment/schemas/fileserver.sql delete mode 100644 deployment/deployment/schemas/flow.sql delete mode 100644 deployment/deployment/schemas/form.sql delete mode 100644 deployment/deployment/schemas/goalie.sql delete mode 100644 deployment/deployment/schemas/kms.sql delete mode 100644 deployment/deployment/schemas/message.sql delete mode 100644 deployment/deployment/schemas/organizations.sql delete mode 100644 deployment/deployment/schemas/polyapi.sql delete mode 100644 deployment/deployment/schemas/process.sql delete mode 100644 deployment/deployment/search_index/Chart.yaml delete mode 100644 deployment/deployment/search_index/templates/_helpers.tpl delete mode 100644 deployment/deployment/search_index/templates/job.yaml delete mode 100644 deployment/deployment/search_index/values.yaml delete mode 100644 deployment/go.mod delete mode 100644 deployment/go.sum delete mode 100644 deployment/main.go delete mode 100644 deployment/pkg/configMysql.go delete mode 100644 deployment/pkg/configs.go delete mode 100644 deployment/pkg/execcmd.go delete mode 100644 deployment/pkg/importImages.go delete mode 100644 deployment/pkg/installFaas.go delete mode 100644 deployment/pkg/middlerwareInstall.go delete mode 100644 deployment/pkg/modifyValues.go delete mode 100644 deployment/pkg/startInstall.go delete mode 100644 deployment/pkg/statusCheck.go delete mode 100644 deployment/pkg/testCondition.go delete mode 100644 deployment/pkg/uninstall.go delete mode 100644 deployment/scripts/init-artery-engine-persona.js delete mode 100644 deployment/scripts/init_nav.js diff --git a/deployment/deployment/middleware_deployment/dapr/.helmignore b/deployment/charts/dapr/.helmignore similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/.helmignore rename to deployment/charts/dapr/.helmignore diff --git a/deployment/deployment/middleware_deployment/dapr/Chart.yaml b/deployment/charts/dapr/Chart.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/Chart.yaml rename to deployment/charts/dapr/Chart.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/README.md b/deployment/charts/dapr/README.md similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/README.md rename to deployment/charts/dapr/README.md diff --git a/deployment/deployment/kibana/.helmignore b/deployment/charts/dapr/charts/dapr_config/.helmignore similarity index 100% rename from deployment/deployment/kibana/.helmignore rename to deployment/charts/dapr/charts/dapr_config/.helmignore diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_config/Chart.yaml b/deployment/charts/dapr/charts/dapr_config/Chart.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_config/Chart.yaml rename to deployment/charts/dapr/charts/dapr_config/Chart.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_config/templates/_helpers.tpl b/deployment/charts/dapr/charts/dapr_config/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_config/templates/_helpers.tpl rename to deployment/charts/dapr/charts/dapr_config/templates/_helpers.tpl diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_config/templates/dapr_default_config.yaml b/deployment/charts/dapr/charts/dapr_config/templates/dapr_default_config.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_config/templates/dapr_default_config.yaml rename to deployment/charts/dapr/charts/dapr_config/templates/dapr_default_config.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_config/values.yaml b/deployment/charts/dapr/charts/dapr_config/values.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_config/values.yaml rename to deployment/charts/dapr/charts/dapr_config/values.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_config/.helmignore b/deployment/charts/dapr/charts/dapr_dashboard/.helmignore similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_config/.helmignore rename to deployment/charts/dapr/charts/dapr_dashboard/.helmignore diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_dashboard/Chart.yaml b/deployment/charts/dapr/charts/dapr_dashboard/Chart.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_dashboard/Chart.yaml rename to deployment/charts/dapr/charts/dapr_dashboard/Chart.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_dashboard/templates/_helpers.tpl b/deployment/charts/dapr/charts/dapr_dashboard/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_dashboard/templates/_helpers.tpl rename to deployment/charts/dapr/charts/dapr_dashboard/templates/_helpers.tpl diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_dashboard/templates/dapr_dashboard_deployment.yaml b/deployment/charts/dapr/charts/dapr_dashboard/templates/dapr_dashboard_deployment.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_dashboard/templates/dapr_dashboard_deployment.yaml rename to deployment/charts/dapr/charts/dapr_dashboard/templates/dapr_dashboard_deployment.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_dashboard/templates/dapr_dashboard_poddisruptionbudget.yaml b/deployment/charts/dapr/charts/dapr_dashboard/templates/dapr_dashboard_poddisruptionbudget.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_dashboard/templates/dapr_dashboard_poddisruptionbudget.yaml rename to deployment/charts/dapr/charts/dapr_dashboard/templates/dapr_dashboard_poddisruptionbudget.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_dashboard/templates/dapr_dashboard_service.yaml b/deployment/charts/dapr/charts/dapr_dashboard/templates/dapr_dashboard_service.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_dashboard/templates/dapr_dashboard_service.yaml rename to deployment/charts/dapr/charts/dapr_dashboard/templates/dapr_dashboard_service.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_dashboard/values.yaml b/deployment/charts/dapr/charts/dapr_dashboard/values.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_dashboard/values.yaml rename to deployment/charts/dapr/charts/dapr_dashboard/values.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_dashboard/.helmignore b/deployment/charts/dapr/charts/dapr_operator/.helmignore similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_dashboard/.helmignore rename to deployment/charts/dapr/charts/dapr_operator/.helmignore diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_operator/Chart.yaml b/deployment/charts/dapr/charts/dapr_operator/Chart.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_operator/Chart.yaml rename to deployment/charts/dapr/charts/dapr_operator/Chart.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_operator/templates/_helpers.tpl b/deployment/charts/dapr/charts/dapr_operator/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_operator/templates/_helpers.tpl rename to deployment/charts/dapr/charts/dapr_operator/templates/_helpers.tpl diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_operator/templates/dapr_operator_deployment.yaml b/deployment/charts/dapr/charts/dapr_operator/templates/dapr_operator_deployment.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_operator/templates/dapr_operator_deployment.yaml rename to deployment/charts/dapr/charts/dapr_operator/templates/dapr_operator_deployment.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_operator/templates/dapr_operator_poddisruptionbudget.yaml b/deployment/charts/dapr/charts/dapr_operator/templates/dapr_operator_poddisruptionbudget.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_operator/templates/dapr_operator_poddisruptionbudget.yaml rename to deployment/charts/dapr/charts/dapr_operator/templates/dapr_operator_poddisruptionbudget.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_operator/templates/dapr_operator_service.yaml b/deployment/charts/dapr/charts/dapr_operator/templates/dapr_operator_service.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_operator/templates/dapr_operator_service.yaml rename to deployment/charts/dapr/charts/dapr_operator/templates/dapr_operator_service.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_operator/values.yaml b/deployment/charts/dapr/charts/dapr_operator/values.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_operator/values.yaml rename to deployment/charts/dapr/charts/dapr_operator/values.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_operator/.helmignore b/deployment/charts/dapr/charts/dapr_placement/.helmignore similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_operator/.helmignore rename to deployment/charts/dapr/charts/dapr_placement/.helmignore diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_placement/Chart.yaml b/deployment/charts/dapr/charts/dapr_placement/Chart.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_placement/Chart.yaml rename to deployment/charts/dapr/charts/dapr_placement/Chart.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_placement/templates/_helpers.tpl b/deployment/charts/dapr/charts/dapr_placement/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_placement/templates/_helpers.tpl rename to deployment/charts/dapr/charts/dapr_placement/templates/_helpers.tpl diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_placement/templates/dapr_placement_deployment.yaml b/deployment/charts/dapr/charts/dapr_placement/templates/dapr_placement_deployment.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_placement/templates/dapr_placement_deployment.yaml rename to deployment/charts/dapr/charts/dapr_placement/templates/dapr_placement_deployment.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_placement/templates/dapr_placement_poddisruptionbudget.yaml b/deployment/charts/dapr/charts/dapr_placement/templates/dapr_placement_poddisruptionbudget.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_placement/templates/dapr_placement_poddisruptionbudget.yaml rename to deployment/charts/dapr/charts/dapr_placement/templates/dapr_placement_poddisruptionbudget.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_placement/templates/dapr_placement_service.yaml b/deployment/charts/dapr/charts/dapr_placement/templates/dapr_placement_service.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_placement/templates/dapr_placement_service.yaml rename to deployment/charts/dapr/charts/dapr_placement/templates/dapr_placement_service.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_placement/values.yaml b/deployment/charts/dapr/charts/dapr_placement/values.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_placement/values.yaml rename to deployment/charts/dapr/charts/dapr_placement/values.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_placement/.helmignore b/deployment/charts/dapr/charts/dapr_rbac/.helmignore similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_placement/.helmignore rename to deployment/charts/dapr/charts/dapr_rbac/.helmignore diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_rbac/Chart.yaml b/deployment/charts/dapr/charts/dapr_rbac/Chart.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_rbac/Chart.yaml rename to deployment/charts/dapr/charts/dapr_rbac/Chart.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_rbac/templates/ClusterRoleBinding.yaml b/deployment/charts/dapr/charts/dapr_rbac/templates/ClusterRoleBinding.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_rbac/templates/ClusterRoleBinding.yaml rename to deployment/charts/dapr/charts/dapr_rbac/templates/ClusterRoleBinding.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_rbac/templates/ServiceAccount.yaml b/deployment/charts/dapr/charts/dapr_rbac/templates/ServiceAccount.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_rbac/templates/ServiceAccount.yaml rename to deployment/charts/dapr/charts/dapr_rbac/templates/ServiceAccount.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_rbac/templates/_helpers.tpl b/deployment/charts/dapr/charts/dapr_rbac/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_rbac/templates/_helpers.tpl rename to deployment/charts/dapr/charts/dapr_rbac/templates/_helpers.tpl diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_rbac/values.yaml b/deployment/charts/dapr/charts/dapr_rbac/values.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_rbac/values.yaml rename to deployment/charts/dapr/charts/dapr_rbac/values.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_rbac/.helmignore b/deployment/charts/dapr/charts/dapr_sentry/.helmignore similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_rbac/.helmignore rename to deployment/charts/dapr/charts/dapr_sentry/.helmignore diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_sentry/Chart.yaml b/deployment/charts/dapr/charts/dapr_sentry/Chart.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_sentry/Chart.yaml rename to deployment/charts/dapr/charts/dapr_sentry/Chart.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_sentry/templates/_helpers.tpl b/deployment/charts/dapr/charts/dapr_sentry/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_sentry/templates/_helpers.tpl rename to deployment/charts/dapr/charts/dapr_sentry/templates/_helpers.tpl diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_sentry/templates/dapr_sentry_deployment.yaml b/deployment/charts/dapr/charts/dapr_sentry/templates/dapr_sentry_deployment.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_sentry/templates/dapr_sentry_deployment.yaml rename to deployment/charts/dapr/charts/dapr_sentry/templates/dapr_sentry_deployment.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_sentry/templates/dapr_sentry_poddisruptionbudget.yaml b/deployment/charts/dapr/charts/dapr_sentry/templates/dapr_sentry_poddisruptionbudget.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_sentry/templates/dapr_sentry_poddisruptionbudget.yaml rename to deployment/charts/dapr/charts/dapr_sentry/templates/dapr_sentry_poddisruptionbudget.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_sentry/templates/dapr_sentry_service.yaml b/deployment/charts/dapr/charts/dapr_sentry/templates/dapr_sentry_service.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_sentry/templates/dapr_sentry_service.yaml rename to deployment/charts/dapr/charts/dapr_sentry/templates/dapr_sentry_service.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_sentry/values.yaml b/deployment/charts/dapr/charts/dapr_sentry/values.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_sentry/values.yaml rename to deployment/charts/dapr/charts/dapr_sentry/values.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_sentry/.helmignore b/deployment/charts/dapr/charts/dapr_sidecar_injector/.helmignore similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_sentry/.helmignore rename to deployment/charts/dapr/charts/dapr_sidecar_injector/.helmignore diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_sidecar_injector/Chart.yaml b/deployment/charts/dapr/charts/dapr_sidecar_injector/Chart.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_sidecar_injector/Chart.yaml rename to deployment/charts/dapr/charts/dapr_sidecar_injector/Chart.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_deployment.yaml b/deployment/charts/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_deployment.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_deployment.yaml rename to deployment/charts/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_deployment.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_poddisruptionbudget.yaml b/deployment/charts/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_poddisruptionbudget.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_poddisruptionbudget.yaml rename to deployment/charts/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_poddisruptionbudget.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_service.yaml b/deployment/charts/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_service.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_service.yaml rename to deployment/charts/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_service.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_webhook_config.yaml b/deployment/charts/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_webhook_config.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_webhook_config.yaml rename to deployment/charts/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_webhook_config.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_sidecar_injector/values.yaml b/deployment/charts/dapr/charts/dapr_sidecar_injector/values.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_sidecar_injector/values.yaml rename to deployment/charts/dapr/charts/dapr_sidecar_injector/values.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/crds/components.yaml b/deployment/charts/dapr/crds/components.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/crds/components.yaml rename to deployment/charts/dapr/crds/components.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/crds/configuration.yaml b/deployment/charts/dapr/crds/configuration.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/crds/configuration.yaml rename to deployment/charts/dapr/crds/configuration.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/crds/resiliency.yaml b/deployment/charts/dapr/crds/resiliency.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/crds/resiliency.yaml rename to deployment/charts/dapr/crds/resiliency.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/crds/subscription.yaml b/deployment/charts/dapr/crds/subscription.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/crds/subscription.yaml rename to deployment/charts/dapr/crds/subscription.yaml diff --git a/deployment/deployment/middleware_deployment/dapr/templates/_helpers.tpl b/deployment/charts/dapr/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/templates/_helpers.tpl rename to deployment/charts/dapr/templates/_helpers.tpl diff --git a/deployment/deployment/middleware_deployment/dapr/values.yaml b/deployment/charts/dapr/values.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/values.yaml rename to deployment/charts/dapr/values.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/.helmignore b/deployment/charts/elasticsearch/.helmignore similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/.helmignore rename to deployment/charts/elasticsearch/.helmignore diff --git a/deployment/deployment/middleware_deployment/elasticsearch/Chart.lock b/deployment/charts/elasticsearch/Chart.lock similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/Chart.lock rename to deployment/charts/elasticsearch/Chart.lock diff --git a/deployment/deployment/middleware_deployment/elasticsearch/Chart.yaml b/deployment/charts/elasticsearch/Chart.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/Chart.yaml rename to deployment/charts/elasticsearch/Chart.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/README.md b/deployment/charts/elasticsearch/README.md similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/README.md rename to deployment/charts/elasticsearch/README.md diff --git a/deployment/deployment/middleware_deployment/dapr/charts/dapr_sidecar_injector/.helmignore b/deployment/charts/elasticsearch/charts/common/.helmignore similarity index 100% rename from deployment/deployment/middleware_deployment/dapr/charts/dapr_sidecar_injector/.helmignore rename to deployment/charts/elasticsearch/charts/common/.helmignore diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/Chart.yaml b/deployment/charts/elasticsearch/charts/common/Chart.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/Chart.yaml rename to deployment/charts/elasticsearch/charts/common/Chart.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/README.md b/deployment/charts/elasticsearch/charts/common/README.md similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/README.md rename to deployment/charts/elasticsearch/charts/common/README.md diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_affinities.tpl b/deployment/charts/elasticsearch/charts/common/templates/_affinities.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_affinities.tpl rename to deployment/charts/elasticsearch/charts/common/templates/_affinities.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_capabilities.tpl b/deployment/charts/elasticsearch/charts/common/templates/_capabilities.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_capabilities.tpl rename to deployment/charts/elasticsearch/charts/common/templates/_capabilities.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_errors.tpl b/deployment/charts/elasticsearch/charts/common/templates/_errors.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_errors.tpl rename to deployment/charts/elasticsearch/charts/common/templates/_errors.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_images.tpl b/deployment/charts/elasticsearch/charts/common/templates/_images.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_images.tpl rename to deployment/charts/elasticsearch/charts/common/templates/_images.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_ingress.tpl b/deployment/charts/elasticsearch/charts/common/templates/_ingress.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_ingress.tpl rename to deployment/charts/elasticsearch/charts/common/templates/_ingress.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_labels.tpl b/deployment/charts/elasticsearch/charts/common/templates/_labels.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_labels.tpl rename to deployment/charts/elasticsearch/charts/common/templates/_labels.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_names.tpl b/deployment/charts/elasticsearch/charts/common/templates/_names.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_names.tpl rename to deployment/charts/elasticsearch/charts/common/templates/_names.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_secrets.tpl b/deployment/charts/elasticsearch/charts/common/templates/_secrets.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_secrets.tpl rename to deployment/charts/elasticsearch/charts/common/templates/_secrets.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_storage.tpl b/deployment/charts/elasticsearch/charts/common/templates/_storage.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_storage.tpl rename to deployment/charts/elasticsearch/charts/common/templates/_storage.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_tplvalues.tpl b/deployment/charts/elasticsearch/charts/common/templates/_tplvalues.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_tplvalues.tpl rename to deployment/charts/elasticsearch/charts/common/templates/_tplvalues.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_utils.tpl b/deployment/charts/elasticsearch/charts/common/templates/_utils.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_utils.tpl rename to deployment/charts/elasticsearch/charts/common/templates/_utils.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_warnings.tpl b/deployment/charts/elasticsearch/charts/common/templates/_warnings.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/_warnings.tpl rename to deployment/charts/elasticsearch/charts/common/templates/_warnings.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/validations/_cassandra.tpl b/deployment/charts/elasticsearch/charts/common/templates/validations/_cassandra.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/validations/_cassandra.tpl rename to deployment/charts/elasticsearch/charts/common/templates/validations/_cassandra.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/validations/_mariadb.tpl b/deployment/charts/elasticsearch/charts/common/templates/validations/_mariadb.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/validations/_mariadb.tpl rename to deployment/charts/elasticsearch/charts/common/templates/validations/_mariadb.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/validations/_mongodb.tpl b/deployment/charts/elasticsearch/charts/common/templates/validations/_mongodb.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/validations/_mongodb.tpl rename to deployment/charts/elasticsearch/charts/common/templates/validations/_mongodb.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/validations/_postgresql.tpl b/deployment/charts/elasticsearch/charts/common/templates/validations/_postgresql.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/validations/_postgresql.tpl rename to deployment/charts/elasticsearch/charts/common/templates/validations/_postgresql.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/validations/_redis.tpl b/deployment/charts/elasticsearch/charts/common/templates/validations/_redis.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/validations/_redis.tpl rename to deployment/charts/elasticsearch/charts/common/templates/validations/_redis.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/validations/_validations.tpl b/deployment/charts/elasticsearch/charts/common/templates/validations/_validations.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/templates/validations/_validations.tpl rename to deployment/charts/elasticsearch/charts/common/templates/validations/_validations.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/values.yaml b/deployment/charts/elasticsearch/charts/common/values.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/values.yaml rename to deployment/charts/elasticsearch/charts/common/values.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/.helmignore b/deployment/charts/elasticsearch/charts/kibana/.helmignore similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/.helmignore rename to deployment/charts/elasticsearch/charts/kibana/.helmignore diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/Chart.lock b/deployment/charts/elasticsearch/charts/kibana/Chart.lock similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/Chart.lock rename to deployment/charts/elasticsearch/charts/kibana/Chart.lock diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/Chart.yaml b/deployment/charts/elasticsearch/charts/kibana/Chart.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/Chart.yaml rename to deployment/charts/elasticsearch/charts/kibana/Chart.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/README.md b/deployment/charts/elasticsearch/charts/kibana/README.md similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/README.md rename to deployment/charts/elasticsearch/charts/kibana/README.md diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/common/.helmignore b/deployment/charts/elasticsearch/charts/kibana/charts/common/.helmignore similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/common/.helmignore rename to deployment/charts/elasticsearch/charts/kibana/charts/common/.helmignore diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/Chart.yaml b/deployment/charts/elasticsearch/charts/kibana/charts/common/Chart.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/Chart.yaml rename to deployment/charts/elasticsearch/charts/kibana/charts/common/Chart.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/README.md b/deployment/charts/elasticsearch/charts/kibana/charts/common/README.md similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/README.md rename to deployment/charts/elasticsearch/charts/kibana/charts/common/README.md diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_affinities.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_affinities.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_affinities.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_affinities.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_capabilities.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_capabilities.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_capabilities.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_capabilities.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_errors.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_errors.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_errors.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_errors.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_images.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_images.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_images.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_images.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_ingress.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_ingress.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_ingress.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_ingress.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_labels.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_labels.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_labels.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_labels.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_names.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_names.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_names.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_names.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_secrets.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_secrets.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_secrets.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_secrets.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_storage.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_storage.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_storage.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_storage.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_tplvalues.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_tplvalues.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_tplvalues.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_tplvalues.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_utils.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_utils.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_utils.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_utils.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_warnings.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_warnings.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/_warnings.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/_warnings.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/validations/_cassandra.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/validations/_cassandra.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/validations/_cassandra.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/validations/_cassandra.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/validations/_mariadb.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/validations/_mariadb.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/validations/_mariadb.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/validations/_mariadb.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/validations/_mongodb.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/validations/_mongodb.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/validations/_mongodb.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/validations/_mongodb.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/validations/_postgresql.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/validations/_postgresql.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/validations/_postgresql.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/validations/_postgresql.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/validations/_redis.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/validations/_redis.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/validations/_redis.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/validations/_redis.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/validations/_validations.tpl b/deployment/charts/elasticsearch/charts/kibana/charts/common/templates/validations/_validations.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/templates/validations/_validations.tpl rename to deployment/charts/elasticsearch/charts/kibana/charts/common/templates/validations/_validations.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/values.yaml b/deployment/charts/elasticsearch/charts/kibana/charts/common/values.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/values.yaml rename to deployment/charts/elasticsearch/charts/kibana/charts/common/values.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/ci/values-with-es.yaml b/deployment/charts/elasticsearch/charts/kibana/ci/values-with-es.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/ci/values-with-es.yaml rename to deployment/charts/elasticsearch/charts/kibana/ci/values-with-es.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/NOTES.txt b/deployment/charts/elasticsearch/charts/kibana/templates/NOTES.txt similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/NOTES.txt rename to deployment/charts/elasticsearch/charts/kibana/templates/NOTES.txt diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/_helpers.tpl b/deployment/charts/elasticsearch/charts/kibana/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/_helpers.tpl rename to deployment/charts/elasticsearch/charts/kibana/templates/_helpers.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/configmap.yaml b/deployment/charts/elasticsearch/charts/kibana/templates/configmap.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/configmap.yaml rename to deployment/charts/elasticsearch/charts/kibana/templates/configmap.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/deployment.yaml b/deployment/charts/elasticsearch/charts/kibana/templates/deployment.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/deployment.yaml rename to deployment/charts/elasticsearch/charts/kibana/templates/deployment.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/extra-list.yaml b/deployment/charts/elasticsearch/charts/kibana/templates/extra-list.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/extra-list.yaml rename to deployment/charts/elasticsearch/charts/kibana/templates/extra-list.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/ingress.yaml b/deployment/charts/elasticsearch/charts/kibana/templates/ingress.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/ingress.yaml rename to deployment/charts/elasticsearch/charts/kibana/templates/ingress.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/plugins-configmap.yaml b/deployment/charts/elasticsearch/charts/kibana/templates/plugins-configmap.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/plugins-configmap.yaml rename to deployment/charts/elasticsearch/charts/kibana/templates/plugins-configmap.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/pvc.yaml b/deployment/charts/elasticsearch/charts/kibana/templates/pvc.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/pvc.yaml rename to deployment/charts/elasticsearch/charts/kibana/templates/pvc.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/saved-objects-configmap.yaml b/deployment/charts/elasticsearch/charts/kibana/templates/saved-objects-configmap.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/saved-objects-configmap.yaml rename to deployment/charts/elasticsearch/charts/kibana/templates/saved-objects-configmap.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/secret.yaml b/deployment/charts/elasticsearch/charts/kibana/templates/secret.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/secret.yaml rename to deployment/charts/elasticsearch/charts/kibana/templates/secret.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/service.yaml b/deployment/charts/elasticsearch/charts/kibana/templates/service.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/service.yaml rename to deployment/charts/elasticsearch/charts/kibana/templates/service.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/serviceaccount.yaml b/deployment/charts/elasticsearch/charts/kibana/templates/serviceaccount.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/serviceaccount.yaml rename to deployment/charts/elasticsearch/charts/kibana/templates/serviceaccount.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/servicemonitor.yaml b/deployment/charts/elasticsearch/charts/kibana/templates/servicemonitor.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/servicemonitor.yaml rename to deployment/charts/elasticsearch/charts/kibana/templates/servicemonitor.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/tls-secret.yaml b/deployment/charts/elasticsearch/charts/kibana/templates/tls-secret.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/templates/tls-secret.yaml rename to deployment/charts/elasticsearch/charts/kibana/templates/tls-secret.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/values.yaml b/deployment/charts/elasticsearch/charts/kibana/values.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/values.yaml rename to deployment/charts/elasticsearch/charts/kibana/values.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/ci/ct-values.yaml b/deployment/charts/elasticsearch/ci/ct-values.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/ci/ct-values.yaml rename to deployment/charts/elasticsearch/ci/ct-values.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/NOTES.txt b/deployment/charts/elasticsearch/templates/NOTES.txt similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/NOTES.txt rename to deployment/charts/elasticsearch/templates/NOTES.txt diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/_helpers.tpl b/deployment/charts/elasticsearch/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/_helpers.tpl rename to deployment/charts/elasticsearch/templates/_helpers.tpl diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/configmap-curator.yaml b/deployment/charts/elasticsearch/templates/configmap-curator.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/configmap-curator.yaml rename to deployment/charts/elasticsearch/templates/configmap-curator.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/configmap-es.yaml b/deployment/charts/elasticsearch/templates/configmap-es.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/configmap-es.yaml rename to deployment/charts/elasticsearch/templates/configmap-es.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/configmap-initscripts.yaml b/deployment/charts/elasticsearch/templates/configmap-initscripts.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/configmap-initscripts.yaml rename to deployment/charts/elasticsearch/templates/configmap-initscripts.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/coordinating-hpa.yaml b/deployment/charts/elasticsearch/templates/coordinating-hpa.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/coordinating-hpa.yaml rename to deployment/charts/elasticsearch/templates/coordinating-hpa.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/coordinating-statefulset.yaml b/deployment/charts/elasticsearch/templates/coordinating-statefulset.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/coordinating-statefulset.yaml rename to deployment/charts/elasticsearch/templates/coordinating-statefulset.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/coordinating-svc.yaml b/deployment/charts/elasticsearch/templates/coordinating-svc.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/coordinating-svc.yaml rename to deployment/charts/elasticsearch/templates/coordinating-svc.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/cronjob.yaml b/deployment/charts/elasticsearch/templates/cronjob.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/cronjob.yaml rename to deployment/charts/elasticsearch/templates/cronjob.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/data-hpa.yaml b/deployment/charts/elasticsearch/templates/data-hpa.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/data-hpa.yaml rename to deployment/charts/elasticsearch/templates/data-hpa.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/data-statefulset.yaml b/deployment/charts/elasticsearch/templates/data-statefulset.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/data-statefulset.yaml rename to deployment/charts/elasticsearch/templates/data-statefulset.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/data-svc.yaml b/deployment/charts/elasticsearch/templates/data-svc.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/data-svc.yaml rename to deployment/charts/elasticsearch/templates/data-svc.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/extra-list.yaml b/deployment/charts/elasticsearch/templates/extra-list.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/extra-list.yaml rename to deployment/charts/elasticsearch/templates/extra-list.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/hooks/job.install.yaml b/deployment/charts/elasticsearch/templates/hooks/job.install.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/hooks/job.install.yaml rename to deployment/charts/elasticsearch/templates/hooks/job.install.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/ingest-statefulset.yaml b/deployment/charts/elasticsearch/templates/ingest-statefulset.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/ingest-statefulset.yaml rename to deployment/charts/elasticsearch/templates/ingest-statefulset.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/ingest-svc.yaml b/deployment/charts/elasticsearch/templates/ingest-svc.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/ingest-svc.yaml rename to deployment/charts/elasticsearch/templates/ingest-svc.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/ingress.yaml b/deployment/charts/elasticsearch/templates/ingress.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/ingress.yaml rename to deployment/charts/elasticsearch/templates/ingress.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/master-hpa.yaml b/deployment/charts/elasticsearch/templates/master-hpa.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/master-hpa.yaml rename to deployment/charts/elasticsearch/templates/master-hpa.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/master-statefulset.yaml b/deployment/charts/elasticsearch/templates/master-statefulset.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/master-statefulset.yaml rename to deployment/charts/elasticsearch/templates/master-statefulset.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/master-svc.yaml b/deployment/charts/elasticsearch/templates/master-svc.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/master-svc.yaml rename to deployment/charts/elasticsearch/templates/master-svc.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/metrics-deploy.yaml b/deployment/charts/elasticsearch/templates/metrics-deploy.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/metrics-deploy.yaml rename to deployment/charts/elasticsearch/templates/metrics-deploy.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/metrics-svc.yaml b/deployment/charts/elasticsearch/templates/metrics-svc.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/metrics-svc.yaml rename to deployment/charts/elasticsearch/templates/metrics-svc.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/podsecuritypolicy.yaml b/deployment/charts/elasticsearch/templates/podsecuritypolicy.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/podsecuritypolicy.yaml rename to deployment/charts/elasticsearch/templates/podsecuritypolicy.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/role.yaml b/deployment/charts/elasticsearch/templates/role.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/role.yaml rename to deployment/charts/elasticsearch/templates/role.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/rolebinding.yaml b/deployment/charts/elasticsearch/templates/rolebinding.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/rolebinding.yaml rename to deployment/charts/elasticsearch/templates/rolebinding.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/secrets.yaml b/deployment/charts/elasticsearch/templates/secrets.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/secrets.yaml rename to deployment/charts/elasticsearch/templates/secrets.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/serviceaccount.yaml b/deployment/charts/elasticsearch/templates/serviceaccount.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/serviceaccount.yaml rename to deployment/charts/elasticsearch/templates/serviceaccount.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/servicemonitor.yaml b/deployment/charts/elasticsearch/templates/servicemonitor.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/servicemonitor.yaml rename to deployment/charts/elasticsearch/templates/servicemonitor.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/templates/tls-secret.yaml b/deployment/charts/elasticsearch/templates/tls-secret.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/templates/tls-secret.yaml rename to deployment/charts/elasticsearch/templates/tls-secret.yaml diff --git a/deployment/deployment/middleware_deployment/elasticsearch/values.yaml b/deployment/charts/elasticsearch/values.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/values.yaml rename to deployment/charts/elasticsearch/values.yaml diff --git a/deployment/deployment/quanxiang_charts/fluent-bit/Chart.yaml b/deployment/charts/fluent-bit/Chart.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/fluent-bit/Chart.yaml rename to deployment/charts/fluent-bit/Chart.yaml diff --git a/deployment/deployment/quanxiang_charts/fluent-bit/README.md b/deployment/charts/fluent-bit/README.md similarity index 100% rename from deployment/deployment/quanxiang_charts/fluent-bit/README.md rename to deployment/charts/fluent-bit/README.md diff --git a/deployment/deployment/quanxiang_charts/fluent-bit/templates/_helpers.tpl b/deployment/charts/fluent-bit/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/fluent-bit/templates/_helpers.tpl rename to deployment/charts/fluent-bit/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/fluent-bit/templates/cluster-role.yaml b/deployment/charts/fluent-bit/templates/cluster-role.yaml similarity index 94% rename from deployment/deployment/quanxiang_charts/fluent-bit/templates/cluster-role.yaml rename to deployment/charts/fluent-bit/templates/cluster-role.yaml index 69c7989..04a260e 100755 --- a/deployment/deployment/quanxiang_charts/fluent-bit/templates/cluster-role.yaml +++ b/deployment/charts/fluent-bit/templates/cluster-role.yaml @@ -8,6 +8,7 @@ metadata: heritage: {{ .Release.Service }} release: {{ .Release.Name }} name: {{ template "fluent-bit.fullname" . }} + namespace: {{ .Values.namespace }} rules: - apiGroups: - "" diff --git a/deployment/deployment/quanxiang_charts/fluent-bit/templates/cluster-rolebinding.yaml b/deployment/charts/fluent-bit/templates/cluster-rolebinding.yaml similarity index 94% rename from deployment/deployment/quanxiang_charts/fluent-bit/templates/cluster-rolebinding.yaml rename to deployment/charts/fluent-bit/templates/cluster-rolebinding.yaml index 140e527..341b277 100755 --- a/deployment/deployment/quanxiang_charts/fluent-bit/templates/cluster-rolebinding.yaml +++ b/deployment/charts/fluent-bit/templates/cluster-rolebinding.yaml @@ -8,6 +8,7 @@ metadata: heritage: {{ .Release.Service }} release: {{ .Release.Name }} name: {{ template "fluent-bit.fullname" . }} + namespace: {{ .Values.namespace }} roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/deployment/deployment/quanxiang_charts/fluent-bit/templates/daemonset.yaml b/deployment/charts/fluent-bit/templates/daemonset.yaml similarity index 99% rename from deployment/deployment/quanxiang_charts/fluent-bit/templates/daemonset.yaml rename to deployment/charts/fluent-bit/templates/daemonset.yaml index b06728b..9025d5a 100755 --- a/deployment/deployment/quanxiang_charts/fluent-bit/templates/daemonset.yaml +++ b/deployment/charts/fluent-bit/templates/daemonset.yaml @@ -2,6 +2,7 @@ apiVersion: {{ template "daemonSet.apiVersion" . }} kind: DaemonSet metadata: name: {{ template "fluent-bit.fullname" . }} + namespace: {{ .Values.namespace }} labels: app: {{ template "fluent-bit.name" . }} chart: {{ .Chart.Name }}-{{ .Chart.Version }} diff --git a/deployment/deployment/quanxiang_charts/fluent-bit/templates/fluent-bit-secret.yaml b/deployment/charts/fluent-bit/templates/fluent-bit-secret.yaml similarity index 98% rename from deployment/deployment/quanxiang_charts/fluent-bit/templates/fluent-bit-secret.yaml rename to deployment/charts/fluent-bit/templates/fluent-bit-secret.yaml index a5f75be..1ed592b 100755 --- a/deployment/deployment/quanxiang_charts/fluent-bit/templates/fluent-bit-secret.yaml +++ b/deployment/charts/fluent-bit/templates/fluent-bit-secret.yaml @@ -3,6 +3,7 @@ apiVersion: v1 kind: Secret metadata: name: {{ template "fluent-bit.fullname" . }}-config + namespace: {{ .Values.namespace }} type: Opaque stringData: fluent-bit.conf: | diff --git a/deployment/deployment/quanxiang_charts/fluent-bit/templates/psp.yaml b/deployment/charts/fluent-bit/templates/psp.yaml similarity index 97% rename from deployment/deployment/quanxiang_charts/fluent-bit/templates/psp.yaml rename to deployment/charts/fluent-bit/templates/psp.yaml index 67065b6..ac90c1c 100755 --- a/deployment/deployment/quanxiang_charts/fluent-bit/templates/psp.yaml +++ b/deployment/charts/fluent-bit/templates/psp.yaml @@ -3,6 +3,7 @@ apiVersion: policy/v1beta1 kind: PodSecurityPolicy metadata: name: {{ template "fluent-bit.fullname" . }} + namespace: {{ .Values.namespace }} spec: # Prevents running in privileged mode privileged: false diff --git a/deployment/deployment/quanxiang_charts/fluent-bit/templates/secret.yaml b/deployment/charts/fluent-bit/templates/secret.yaml similarity index 96% rename from deployment/deployment/quanxiang_charts/fluent-bit/templates/secret.yaml rename to deployment/charts/fluent-bit/templates/secret.yaml index 890747d..7007047 100755 --- a/deployment/deployment/quanxiang_charts/fluent-bit/templates/secret.yaml +++ b/deployment/charts/fluent-bit/templates/secret.yaml @@ -4,6 +4,7 @@ apiVersion: v1 kind: Secret metadata: name: "{{ template "fluent-bit.fullname" . }}-es-tls-secret" + namespace: {{ .Values.namespace }} labels: app: {{ template "fluent-bit.name" . }} chart: {{ .Chart.Name }}-{{ .Chart.Version }} diff --git a/deployment/deployment/quanxiang_charts/fluent-bit/templates/service.yaml b/deployment/charts/fluent-bit/templates/service.yaml similarity index 95% rename from deployment/deployment/quanxiang_charts/fluent-bit/templates/service.yaml rename to deployment/charts/fluent-bit/templates/service.yaml index 8bbc88f..48f426b 100755 --- a/deployment/deployment/quanxiang_charts/fluent-bit/templates/service.yaml +++ b/deployment/charts/fluent-bit/templates/service.yaml @@ -7,6 +7,7 @@ metadata: {{ toYaml .Values.metrics.service.annotations | indent 4 }} {{- end }} name: {{ template "fluent-bit.fullname" . }}-metrics + namespace: {{ .Values.namespace }} labels: app: {{ template "fluent-bit.name" . }} chart: {{ .Chart.Name }}-{{ .Chart.Version }} diff --git a/deployment/deployment/quanxiang_charts/fluent-bit/templates/serviceaccount.yaml b/deployment/charts/fluent-bit/templates/serviceaccount.yaml similarity index 92% rename from deployment/deployment/quanxiang_charts/fluent-bit/templates/serviceaccount.yaml rename to deployment/charts/fluent-bit/templates/serviceaccount.yaml index 1a1b1a0..c156e96 100755 --- a/deployment/deployment/quanxiang_charts/fluent-bit/templates/serviceaccount.yaml +++ b/deployment/charts/fluent-bit/templates/serviceaccount.yaml @@ -8,6 +8,7 @@ metadata: heritage: {{ .Release.Service }} release: {{ .Release.Name }} name: {{ template "fluent-bit.serviceAccountName" . }} + namespace: {{ .Values.namespace }} {{- with .Values.serviceAccount.annotations }} annotations: {{- toYaml . | nindent 4 }} diff --git a/deployment/deployment/quanxiang_charts/fluent-bit/templates/servicemonitor.yaml b/deployment/charts/fluent-bit/templates/servicemonitor.yaml similarity index 96% rename from deployment/deployment/quanxiang_charts/fluent-bit/templates/servicemonitor.yaml rename to deployment/charts/fluent-bit/templates/servicemonitor.yaml index df0a03c..c913b02 100755 --- a/deployment/deployment/quanxiang_charts/fluent-bit/templates/servicemonitor.yaml +++ b/deployment/charts/fluent-bit/templates/servicemonitor.yaml @@ -5,6 +5,8 @@ metadata: name: {{ include "fluent-bit.fullname" . }} {{- if .Values.metrics.serviceMonitor.namespace }} namespace: {{ .Values.metrics.serviceMonitor.namespace }} + {{- else }} + namespace: {{ .Values.namespace }} {{- end }} labels: app: {{ template "fluent-bit.name" . }} diff --git a/deployment/deployment/quanxiang_charts/fluent-bit/templates/tests/test-configmap.yaml b/deployment/charts/fluent-bit/templates/tests/test-configmap.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/fluent-bit/templates/tests/test-configmap.yaml rename to deployment/charts/fluent-bit/templates/tests/test-configmap.yaml diff --git a/deployment/deployment/quanxiang_charts/fluent-bit/templates/tests/test.yaml b/deployment/charts/fluent-bit/templates/tests/test.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/fluent-bit/templates/tests/test.yaml rename to deployment/charts/fluent-bit/templates/tests/test.yaml diff --git a/deployment/deployment/quanxiang_charts/fluent-bit/values.yaml b/deployment/charts/fluent-bit/values.yaml similarity index 99% rename from deployment/deployment/quanxiang_charts/fluent-bit/values.yaml rename to deployment/charts/fluent-bit/values.yaml index a56e635..8cb044a 100755 --- a/deployment/deployment/quanxiang_charts/fluent-bit/values.yaml +++ b/deployment/charts/fluent-bit/values.yaml @@ -1,7 +1,7 @@ # Minikube stores its logs in a separate directory. # Enable if you install the chart in minikube. on_minikube: false - +namespace: builder image: fluent_bit: repository: fluent/fluent-bit diff --git a/deployment/deployment/middleware_deployment/kafka/.helmignore b/deployment/charts/kafka/.helmignore similarity index 100% rename from deployment/deployment/middleware_deployment/kafka/.helmignore rename to deployment/charts/kafka/.helmignore diff --git a/deployment/charts/kafka/Chart.lock b/deployment/charts/kafka/Chart.lock new file mode 100644 index 0000000..4f0ea01 --- /dev/null +++ b/deployment/charts/kafka/Chart.lock @@ -0,0 +1,9 @@ +dependencies: +- name: zookeeper + repository: https://charts.bitnami.com/bitnami + version: 11.0.2 +- name: common + repository: https://charts.bitnami.com/bitnami + version: 2.2.2 +digest: sha256:406b7c170751d9aeab272ff010ee5affc4a8b2a4487f0157a68a0f726ff155b6 +generated: "2022-12-18T23:00:36.711399047Z" diff --git a/deployment/charts/kafka/Chart.yaml b/deployment/charts/kafka/Chart.yaml new file mode 100644 index 0000000..cee687d --- /dev/null +++ b/deployment/charts/kafka/Chart.yaml @@ -0,0 +1,33 @@ +annotations: + category: Infrastructure +apiVersion: v2 +appVersion: 3.3.1 +dependencies: +- condition: zookeeper.enabled + name: zookeeper + repository: https://charts.bitnami.com/bitnami + version: 11.x.x +- name: common + repository: https://charts.bitnami.com/bitnami + tags: + - bitnami-common + version: 2.x.x +description: Apache Kafka is a distributed streaming platform designed to build real-time + pipelines and can be used as a message broker or as a replacement for a log aggregation + solution for big data applications. +home: https://github.com/bitnami/charts/tree/main/bitnami/kafka +icon: https://bitnami.com/assets/stacks/kafka/img/kafka-stack-220x234.png +keywords: +- kafka +- zookeeper +- streaming +- producer +- consumer +maintainers: +- name: Bitnami + url: https://github.com/bitnami/charts +name: kafka +sources: +- https://github.com/bitnami/containers/tree/main/bitnami/kafka +- https://kafka.apache.org/ +version: 20.0.2 diff --git a/deployment/charts/kafka/README.md b/deployment/charts/kafka/README.md new file mode 100644 index 0000000..5e922e0 --- /dev/null +++ b/deployment/charts/kafka/README.md @@ -0,0 +1,1050 @@ + + +# Apache Kafka packaged by Bitnami + +Apache Kafka is a distributed streaming platform designed to build real-time pipelines and can be used as a message broker or as a replacement for a log aggregation solution for big data applications. + +[Overview of Apache Kafka](http://kafka.apache.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 + +```console +helm repo add my-repo https://charts.bitnami.com/bitnami +helm install my-release my-repo/kafka +``` + +## Introduction + +This chart bootstraps a [Kafka](https://github.com/bitnami/containers/tree/main/bitnami/kafka) deployment on a [Kubernetes](https://kubernetes.io) cluster using the [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+ +- PV provisioner support in the underlying infrastructure + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```console +helm repo add my-repo https://charts.bitnami.com/bitnami +helm install my-release my-repo/kafka +``` + +These commands deploy Kafka 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: + +```console +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 StorageClass for Persistent Volume(s) | `""` | + + +### Common parameters + +| Name | Description | Value | +| ------------------------ | --------------------------------------------------------------------------------------- | --------------- | +| `kubeVersion` | Override Kubernetes version | `""` | +| `nameOverride` | String to partially override common.names.fullname | `""` | +| `fullnameOverride` | String to fully override common.names.fullname | `""` | +| `clusterDomain` | Default Kubernetes cluster domain | `cluster.local` | +| `commonLabels` | Labels to add to all deployed objects | `{}` | +| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | +| `extraDeploy` | Array of extra objects to deploy with the release | `[]` | +| `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 statefulset | `["sleep"]` | +| `diagnosticMode.args` | Args to override all containers in the statefulset | `["infinity"]` | + + +### Kafka parameters + +| Name | Description | Value | +| ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | +| `image.registry` | Kafka image registry | `docker.io` | +| `image.repository` | Kafka image repository | `bitnami/kafka` | +| `image.tag` | Kafka image tag (immutable tags are recommended) | `3.3.1-debian-11-r25` | +| `image.digest` | Kafka image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | +| `image.pullPolicy` | Kafka image pull policy | `IfNotPresent` | +| `image.pullSecrets` | Specify docker-registry secret names as an array | `[]` | +| `image.debug` | Specify if debug values should be set | `false` | +| `config` | Configuration file for Kafka. Auto-generated based on other parameters when not specified | `""` | +| `existingConfigmap` | ConfigMap with Kafka Configuration | `""` | +| `log4j` | An optional log4j.properties file to overwrite the default of the Kafka brokers | `""` | +| `existingLog4jConfigMap` | The name of an existing ConfigMap containing a log4j.properties file | `""` | +| `heapOpts` | Kafka Java Heap size | `-Xmx1024m -Xms1024m` | +| `deleteTopicEnable` | Switch to enable topic deletion or not | `false` | +| `autoCreateTopicsEnable` | Switch to enable auto creation of topics. Enabling auto creation of topics not recommended for production or similar environments | `true` | +| `logFlushIntervalMessages` | The number of messages to accept before forcing a flush of data to disk | `_10000` | +| `logFlushIntervalMs` | The maximum amount of time a message can sit in a log before we force a flush | `1000` | +| `logRetentionBytes` | A size-based retention policy for logs | `_1073741824` | +| `logRetentionCheckIntervalMs` | The interval at which log segments are checked to see if they can be deleted | `300000` | +| `logRetentionHours` | The minimum age of a log file to be eligible for deletion due to age | `168` | +| `logSegmentBytes` | The maximum size of a log segment file. When this size is reached a new log segment will be created | `_1073741824` | +| `logsDirs` | A comma separated list of directories in which kafka's log data is kept | `/bitnami/kafka/data` | +| `maxMessageBytes` | The largest record batch size allowed by Kafka | `_1000012` | +| `defaultReplicationFactor` | Default replication factors for automatically created topics | `1` | +| `offsetsTopicReplicationFactor` | The replication factor for the offsets topic | `1` | +| `transactionStateLogReplicationFactor` | The replication factor for the transaction topic | `1` | +| `transactionStateLogMinIsr` | Overridden min.insync.replicas config for the transaction topic | `1` | +| `numIoThreads` | The number of threads doing disk I/O | `8` | +| `numNetworkThreads` | The number of threads handling network requests | `3` | +| `numPartitions` | The default number of log partitions per topic | `1` | +| `numRecoveryThreadsPerDataDir` | The number of threads per data directory to be used for log recovery at startup and flushing at shutdown | `1` | +| `socketReceiveBufferBytes` | The receive buffer (SO_RCVBUF) used by the socket server | `102400` | +| `socketRequestMaxBytes` | The maximum size of a request that the socket server will accept (protection against OOM) | `_104857600` | +| `socketSendBufferBytes` | The send buffer (SO_SNDBUF) used by the socket server | `102400` | +| `zookeeperConnectionTimeoutMs` | Timeout in ms for connecting to ZooKeeper | `6000` | +| `zookeeperChrootPath` | Path which puts data under some path in the global ZooKeeper namespace | `""` | +| `authorizerClassName` | The Authorizer is configured by setting authorizer.class.name=kafka.security.authorizer.AclAuthorizer in server.properties | `""` | +| `allowEveryoneIfNoAclFound` | By default, if a resource has no associated ACLs, then no one is allowed to access that resource except super users | `true` | +| `superUsers` | You can add super users in server.properties | `User:admin` | +| `auth.clientProtocol` | Authentication protocol for communications with clients. Allowed protocols: `plaintext`, `tls`, `mtls`, `sasl` and `sasl_tls` | `plaintext` | +| `auth.externalClientProtocol` | Authentication protocol for communications with external clients. Defaults to value of `auth.clientProtocol`. Allowed protocols: `plaintext`, `tls`, `mtls`, `sasl` and `sasl_tls` | `""` | +| `auth.interBrokerProtocol` | Authentication protocol for inter-broker communications. Allowed protocols: `plaintext`, `tls`, `mtls`, `sasl` and `sasl_tls` | `plaintext` | +| `auth.sasl.mechanisms` | SASL mechanisms when either `auth.interBrokerProtocol`, `auth.clientProtocol` or `auth.externalClientProtocol` are `sasl`. Allowed types: `plain`, `scram-sha-256`, `scram-sha-512` | `plain,scram-sha-256,scram-sha-512` | +| `auth.sasl.interBrokerMechanism` | SASL mechanism for inter broker communication. | `plain` | +| `auth.sasl.jaas.clientUsers` | Kafka client user list | `["user"]` | +| `auth.sasl.jaas.clientPasswords` | Kafka client passwords. This is mandatory if more than one user is specified in clientUsers | `[]` | +| `auth.sasl.jaas.interBrokerUser` | Kafka inter broker communication user for SASL authentication | `admin` | +| `auth.sasl.jaas.interBrokerPassword` | Kafka inter broker communication password for SASL authentication | `""` | +| `auth.sasl.jaas.zookeeperUser` | Kafka ZooKeeper user for SASL authentication | `""` | +| `auth.sasl.jaas.zookeeperPassword` | Kafka ZooKeeper password for SASL authentication | `""` | +| `auth.sasl.jaas.existingSecret` | Name of the existing secret containing credentials for clientUsers, interBrokerUser and zookeeperUser | `""` | +| `auth.tls.type` | Format to use for TLS certificates. Allowed types: `jks` and `pem` | `jks` | +| `auth.tls.pemChainIncluded` | Flag to denote that the Certificate Authority (CA) certificates are bundled with the endpoint cert. | `false` | +| `auth.tls.existingSecrets` | Array existing secrets containing the TLS certificates for the Kafka brokers | `[]` | +| `auth.tls.autoGenerated` | Generate automatically self-signed TLS certificates for Kafka brokers. Currently only supported if `auth.tls.type` is `pem` | `false` | +| `auth.tls.password` | Password to access the JKS files or PEM key when they are password-protected. | `""` | +| `auth.tls.existingSecret` | Name of the secret containing the password to access the JKS files or PEM key when they are password-protected. (`key`: `password`) | `""` | +| `auth.tls.jksTruststoreSecret` | Name of the existing secret containing your truststore if truststore not existing or different from the ones in the `auth.tls.existingSecrets` | `""` | +| `auth.tls.jksKeystoreSAN` | The secret key from the `auth.tls.existingSecrets` containing the keystore with a SAN certificate | `""` | +| `auth.tls.jksTruststore` | The secret key from the `auth.tls.existingSecrets` or `auth.tls.jksTruststoreSecret` containing the truststore | `""` | +| `auth.tls.endpointIdentificationAlgorithm` | The endpoint identification algorithm to validate server hostname using server certificate | `https` | +| `auth.zookeeper.tls.enabled` | Enable TLS for Zookeeper client connections. | `false` | +| `auth.zookeeper.tls.type` | Format to use for TLS certificates. Allowed types: `jks` and `pem`. | `jks` | +| `auth.zookeeper.tls.verifyHostname` | Hostname validation. | `true` | +| `auth.zookeeper.tls.existingSecret` | Name of the existing secret containing the TLS certificates for ZooKeeper client communications. | `""` | +| `auth.zookeeper.tls.existingSecretKeystoreKey` | The secret key from the auth.zookeeper.tls.existingSecret containing the Keystore. | `zookeeper.keystore.jks` | +| `auth.zookeeper.tls.existingSecretTruststoreKey` | The secret key from the auth.zookeeper.tls.existingSecret containing the Truststore. | `zookeeper.truststore.jks` | +| `auth.zookeeper.tls.passwordsSecret` | Existing secret containing Keystore and Truststore passwords. | `""` | +| `auth.zookeeper.tls.passwordsSecretKeystoreKey` | The secret key from the auth.zookeeper.tls.passwordsSecret containing the password for the Keystore. | `keystore-password` | +| `auth.zookeeper.tls.passwordsSecretTruststoreKey` | The secret key from the auth.zookeeper.tls.passwordsSecret containing the password for the Truststore. | `truststore-password` | +| `listeners` | The address(es) the socket server listens on. Auto-calculated it's set to an empty array | `[]` | +| `advertisedListeners` | The address(es) (hostname:port) the broker will advertise to producers and consumers. Auto-calculated it's set to an empty array | `[]` | +| `listenerSecurityProtocolMap` | The protocol->listener mapping. Auto-calculated it's set to nil | `""` | +| `allowPlaintextListener` | Allow to use the PLAINTEXT listener | `true` | +| `interBrokerListenerName` | The listener that the brokers should communicate on | `INTERNAL` | +| `command` | Override Kafka container command | `["/scripts/setup.sh"]` | +| `args` | Override Kafka container arguments | `[]` | +| `extraEnvVars` | Extra environment variables to add to Kafka pods | `[]` | +| `extraEnvVarsCM` | ConfigMap with extra environment variables | `""` | +| `extraEnvVarsSecret` | Secret with extra environment variables | `""` | + + +### Statefulset parameters + +| Name | Description | Value | +| --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | +| `replicaCount` | Number of Kafka nodes | `1` | +| `minBrokerId` | Minimal broker.id value, nodes increment their `broker.id` respectively | `0` | +| `brokerRackAssignment` | Set Broker Assignment for multi tenant environment Allowed values: `aws-az` | `""` | +| `containerPorts.client` | Kafka client container port | `9092` | +| `containerPorts.internal` | Kafka inter-broker container port | `9093` | +| `containerPorts.external` | Kafka external container port | `9094` | +| `livenessProbe.enabled` | Enable livenessProbe on Kafka containers | `true` | +| `livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `10` | +| `livenessProbe.periodSeconds` | Period seconds for livenessProbe | `10` | +| `livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `5` | +| `livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `3` | +| `livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | +| `readinessProbe.enabled` | Enable readinessProbe on Kafka containers | `true` | +| `readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `5` | +| `readinessProbe.periodSeconds` | Period seconds for readinessProbe | `10` | +| `readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `5` | +| `readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `6` | +| `readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | +| `startupProbe.enabled` | Enable startupProbe on Kafka containers | `false` | +| `startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `30` | +| `startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | +| `startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `1` | +| `startupProbe.failureThreshold` | Failure threshold for startupProbe | `15` | +| `startupProbe.successThreshold` | Success threshold for startupProbe | `1` | +| `customLivenessProbe` | Custom livenessProbe that overrides the default one | `{}` | +| `customReadinessProbe` | Custom readinessProbe that overrides the default one | `{}` | +| `customStartupProbe` | Custom startupProbe that overrides the default one | `{}` | +| `lifecycleHooks` | lifecycleHooks for the Kafka container to automate configuration before or after startup | `{}` | +| `resources.limits` | The resources limits for the container | `{}` | +| `resources.requests` | The requested resources for the container | `{}` | +| `podSecurityContext.enabled` | Enable security context for the pods | `true` | +| `podSecurityContext.fsGroup` | Set Kafka pod's Security Context fsGroup | `1001` | +| `containerSecurityContext.enabled` | Enable Kafka containers' Security Context | `true` | +| `containerSecurityContext.runAsUser` | Set Kafka containers' Security Context runAsUser | `1001` | +| `containerSecurityContext.runAsNonRoot` | Set Kafka containers' Security Context runAsNonRoot | `true` | +| `containerSecurityContext.allowPrivilegeEscalation` | Force the child process to be run as nonprivilege | `false` | +| `hostAliases` | Kafka pods host aliases | `[]` | +| `hostNetwork` | Specify if host network should be enabled for Kafka pods | `false` | +| `hostIPC` | Specify if host IPC should be enabled for Kafka pods | `false` | +| `podLabels` | Extra labels for Kafka pods | `{}` | +| `podAnnotations` | Extra annotations for Kafka pods | `{}` | +| `podAffinityPreset` | Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `podAntiAffinityPreset` | Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `nodeAffinityPreset.type` | Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `nodeAffinityPreset.key` | Node label key to match Ignored if `affinity` is set. | `""` | +| `nodeAffinityPreset.values` | Node label values to match. Ignored if `affinity` is set. | `[]` | +| `affinity` | Affinity for pod assignment | `{}` | +| `nodeSelector` | Node labels for pod assignment | `{}` | +| `tolerations` | Tolerations for pod assignment | `[]` | +| `topologySpreadConstraints` | Topology Spread Constraints for pod assignment spread across your cluster among failure-domains. Evaluated as a template | `[]` | +| `terminationGracePeriodSeconds` | Seconds the pod needs to gracefully terminate | `""` | +| `podManagementPolicy` | StatefulSet controller supports relax its ordering guarantees while preserving its uniqueness and identity guarantees. There are two valid pod management policies: OrderedReady and Parallel | `Parallel` | +| `priorityClassName` | Name of the existing priority class to be used by kafka pods | `""` | +| `schedulerName` | Name of the k8s scheduler (other than default) | `""` | +| `updateStrategy.type` | Kafka statefulset strategy type | `RollingUpdate` | +| `updateStrategy.rollingUpdate` | Kafka statefulset rolling update configuration parameters | `{}` | +| `extraVolumes` | Optionally specify extra list of additional volumes for the Kafka pod(s) | `[]` | +| `extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the Kafka container(s) | `[]` | +| `sidecars` | Add additional sidecar containers to the Kafka pod(s) | `[]` | +| `initContainers` | Add additional Add init containers to the Kafka pod(s) | `[]` | +| `pdb.create` | Deploy a pdb object for the Kafka pod | `false` | +| `pdb.minAvailable` | Maximum number/percentage of unavailable Kafka replicas | `""` | +| `pdb.maxUnavailable` | Maximum number/percentage of unavailable Kafka replicas | `1` | + + +### Traffic Exposure parameters + +| Name | Description | Value | +| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | --------------------- | +| `service.type` | Kubernetes Service type | `ClusterIP` | +| `service.ports.client` | Kafka svc port for client connections | `9092` | +| `service.ports.internal` | Kafka svc port for inter-broker connections | `9093` | +| `service.ports.external` | Kafka svc port for external connections | `9094` | +| `service.nodePorts.client` | Node port for the Kafka client connections | `""` | +| `service.nodePorts.external` | Node port for the Kafka external connections | `""` | +| `service.sessionAffinity` | Control where client requests go, to the same pod or round-robin | `None` | +| `service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | +| `service.clusterIP` | Kafka service Cluster IP | `""` | +| `service.loadBalancerIP` | Kafka service Load Balancer IP | `""` | +| `service.loadBalancerSourceRanges` | Kafka service Load Balancer sources | `[]` | +| `service.externalTrafficPolicy` | Kafka service external traffic policy | `Cluster` | +| `service.annotations` | Additional custom annotations for Kafka service | `{}` | +| `service.headless.publishNotReadyAddresses` | Indicates that any agent which deals with endpoints for this Service should disregard any indications of ready/not-ready | `false` | +| `service.headless.annotations` | Annotations for the headless service. | `{}` | +| `service.headless.labels` | Labels for the headless service. | `{}` | +| `service.extraPorts` | Extra ports to expose in the Kafka service (normally used with the `sidecar` value) | `[]` | +| `externalAccess.enabled` | Enable Kubernetes external cluster access to Kafka brokers | `false` | +| `externalAccess.autoDiscovery.enabled` | Enable using an init container to auto-detect external IPs/ports by querying the K8s API | `false` | +| `externalAccess.autoDiscovery.image.registry` | Init container auto-discovery image registry | `docker.io` | +| `externalAccess.autoDiscovery.image.repository` | Init container auto-discovery image repository | `bitnami/kubectl` | +| `externalAccess.autoDiscovery.image.tag` | Init container auto-discovery image tag (immutable tags are recommended) | `1.25.5-debian-11-r2` | +| `externalAccess.autoDiscovery.image.digest` | Petete image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | +| `externalAccess.autoDiscovery.image.pullPolicy` | Init container auto-discovery image pull policy | `IfNotPresent` | +| `externalAccess.autoDiscovery.image.pullSecrets` | Init container auto-discovery image pull secrets | `[]` | +| `externalAccess.autoDiscovery.resources.limits` | The resources limits for the auto-discovery init container | `{}` | +| `externalAccess.autoDiscovery.resources.requests` | The requested resources for the auto-discovery init container | `{}` | +| `externalAccess.service.type` | Kubernetes Service type for external access. It can be NodePort, LoadBalancer or ClusterIP | `LoadBalancer` | +| `externalAccess.service.ports.external` | Kafka port used for external access when service type is LoadBalancer | `9094` | +| `externalAccess.service.loadBalancerIPs` | Array of load balancer IPs for each Kafka broker. Length must be the same as replicaCount | `[]` | +| `externalAccess.service.loadBalancerNames` | Array of load balancer Names for each Kafka broker. Length must be the same as replicaCount | `[]` | +| `externalAccess.service.loadBalancerAnnotations` | Array of load balancer annotations for each Kafka broker. Length must be the same as replicaCount | `[]` | +| `externalAccess.service.loadBalancerSourceRanges` | Address(es) that are allowed when service is LoadBalancer | `[]` | +| `externalAccess.service.nodePorts` | Array of node ports used for each Kafka broker. Length must be the same as replicaCount | `[]` | +| `externalAccess.service.useHostIPs` | Use service host IPs to configure Kafka external listener when service type is NodePort | `false` | +| `externalAccess.service.usePodIPs` | using the MY_POD_IP address for external access. | `false` | +| `externalAccess.service.domain` | Domain or external ip used to configure Kafka external listener when service type is NodePort or ClusterIP | `""` | +| `externalAccess.service.publishNotReadyAddresses` | Indicates that any agent which deals with endpoints for this Service should disregard any indications of ready/not-ready | `false` | +| `externalAccess.service.labels` | Service labels for external access | `{}` | +| `externalAccess.service.annotations` | Service annotations for external access | `{}` | +| `externalAccess.service.extraPorts` | Extra ports to expose in the Kafka external service | `[]` | +| `networkPolicy.enabled` | Specifies whether a NetworkPolicy should be created | `false` | +| `networkPolicy.allowExternal` | Don't require client label for connections | `true` | +| `networkPolicy.explicitNamespacesSelector` | A Kubernetes LabelSelector to explicitly select namespaces from which traffic could be allowed | `{}` | +| `networkPolicy.externalAccess.from` | customize the from section for External Access on tcp-external port | `[]` | +| `networkPolicy.egressRules.customRules` | Custom network policy rule | `{}` | + + +### Persistence parameters + +| Name | Description | Value | +| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | +| `persistence.enabled` | Enable Kafka data persistence using PVC, note that ZooKeeper persistence is unaffected | `true` | +| `persistence.existingClaim` | A manually managed Persistent Volume and Claim | `""` | +| `persistence.storageClass` | PVC Storage Class for Kafka data volume | `""` | +| `persistence.accessModes` | Persistent Volume Access Modes | `["ReadWriteOnce"]` | +| `persistence.size` | PVC Storage Request for Kafka data volume | `8Gi` | +| `persistence.annotations` | Annotations for the PVC | `{}` | +| `persistence.labels` | Labels for the PVC | `{}` | +| `persistence.selector` | Selector to match an existing Persistent Volume for Kafka data PVC. If set, the PVC can't have a PV dynamically provisioned for it | `{}` | +| `persistence.mountPath` | Mount path of the Kafka data volume | `/bitnami/kafka` | +| `logPersistence.enabled` | Enable Kafka logs persistence using PVC, note that ZooKeeper persistence is unaffected | `false` | +| `logPersistence.existingClaim` | A manually managed Persistent Volume and Claim | `""` | +| `logPersistence.storageClass` | PVC Storage Class for Kafka logs volume | `""` | +| `logPersistence.accessModes` | Persistent Volume Access Modes | `["ReadWriteOnce"]` | +| `logPersistence.size` | PVC Storage Request for Kafka logs volume | `8Gi` | +| `logPersistence.annotations` | Annotations for the PVC | `{}` | +| `logPersistence.selector` | Selector to match an existing Persistent Volume for Kafka log data PVC. If set, the PVC can't have a PV dynamically provisioned for it | `{}` | +| `logPersistence.mountPath` | Mount path of the Kafka logs volume | `/opt/bitnami/kafka/logs` | + + +### Volume Permissions parameters + +| Name | Description | Value | +| ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | +| `volumePermissions.enabled` | Enable init container that changes the owner and group of the persistent volume | `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-r63` | +| `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` | Init container volume-permissions image pull secrets | `[]` | +| `volumePermissions.resources.limits` | Init container volume-permissions resource limits | `{}` | +| `volumePermissions.resources.requests` | Init container volume-permissions resource requests | `{}` | +| `volumePermissions.containerSecurityContext.runAsUser` | User ID for the init container | `0` | + + +### Other Parameters + +| Name | Description | Value | +| --------------------------------------------- | ---------------------------------------------------------------------------------------------- | ------- | +| `serviceAccount.create` | Enable creation of ServiceAccount for Kafka pods | `true` | +| `serviceAccount.name` | The name of the service account to use. If not set and `create` is `true`, a name is generated | `""` | +| `serviceAccount.automountServiceAccountToken` | Allows auto mount of ServiceAccountToken on the serviceAccount created | `true` | +| `serviceAccount.annotations` | Additional custom annotations for the ServiceAccount | `{}` | +| `rbac.create` | Whether to create & use RBAC resources or not | `false` | + + +### Metrics parameters + +| Name | Description | Value | +| ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | +| `metrics.kafka.enabled` | Whether or not to create a standalone Kafka exporter to expose Kafka metrics | `false` | +| `metrics.kafka.image.registry` | Kafka exporter image registry | `docker.io` | +| `metrics.kafka.image.repository` | Kafka exporter image repository | `bitnami/kafka-exporter` | +| `metrics.kafka.image.tag` | Kafka exporter image tag (immutable tags are recommended) | `1.6.0-debian-11-r40` | +| `metrics.kafka.image.digest` | Kafka exporter image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | +| `metrics.kafka.image.pullPolicy` | Kafka exporter image pull policy | `IfNotPresent` | +| `metrics.kafka.image.pullSecrets` | Specify docker-registry secret names as an array | `[]` | +| `metrics.kafka.certificatesSecret` | Name of the existing secret containing the optional certificate and key files | `""` | +| `metrics.kafka.tlsCert` | The secret key from the certificatesSecret if 'client-cert' key different from the default (cert-file) | `cert-file` | +| `metrics.kafka.tlsKey` | The secret key from the certificatesSecret if 'client-key' key different from the default (key-file) | `key-file` | +| `metrics.kafka.tlsCaSecret` | Name of the existing secret containing the optional ca certificate for Kafka exporter client authentication | `""` | +| `metrics.kafka.tlsCaCert` | The secret key from the certificatesSecret or tlsCaSecret if 'ca-cert' key different from the default (ca-file) | `ca-file` | +| `metrics.kafka.extraFlags` | Extra flags to be passed to Kafka exporter | `{}` | +| `metrics.kafka.command` | Override Kafka exporter container command | `[]` | +| `metrics.kafka.args` | Override Kafka exporter container arguments | `[]` | +| `metrics.kafka.containerPorts.metrics` | Kafka exporter metrics container port | `9308` | +| `metrics.kafka.resources.limits` | The resources limits for the container | `{}` | +| `metrics.kafka.resources.requests` | The requested resources for the container | `{}` | +| `metrics.kafka.podSecurityContext.enabled` | Enable security context for the pods | `true` | +| `metrics.kafka.podSecurityContext.fsGroup` | Set Kafka exporter pod's Security Context fsGroup | `1001` | +| `metrics.kafka.containerSecurityContext.enabled` | Enable Kafka exporter containers' Security Context | `true` | +| `metrics.kafka.containerSecurityContext.runAsUser` | Set Kafka exporter containers' Security Context runAsUser | `1001` | +| `metrics.kafka.containerSecurityContext.runAsNonRoot` | Set Kafka exporter containers' Security Context runAsNonRoot | `true` | +| `metrics.kafka.hostAliases` | Kafka exporter pods host aliases | `[]` | +| `metrics.kafka.podLabels` | Extra labels for Kafka exporter pods | `{}` | +| `metrics.kafka.podAnnotations` | Extra annotations for Kafka exporter pods | `{}` | +| `metrics.kafka.podAffinityPreset` | Pod affinity preset. Ignored if `metrics.kafka.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `metrics.kafka.podAntiAffinityPreset` | Pod anti-affinity preset. Ignored if `metrics.kafka.affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `metrics.kafka.nodeAffinityPreset.type` | Node affinity preset type. Ignored if `metrics.kafka.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `metrics.kafka.nodeAffinityPreset.key` | Node label key to match Ignored if `metrics.kafka.affinity` is set. | `""` | +| `metrics.kafka.nodeAffinityPreset.values` | Node label values to match. Ignored if `metrics.kafka.affinity` is set. | `[]` | +| `metrics.kafka.affinity` | Affinity for pod assignment | `{}` | +| `metrics.kafka.nodeSelector` | Node labels for pod assignment | `{}` | +| `metrics.kafka.tolerations` | Tolerations for pod assignment | `[]` | +| `metrics.kafka.schedulerName` | Name of the k8s scheduler (other than default) for Kafka exporter | `""` | +| `metrics.kafka.priorityClassName` | Kafka exporter pods' priorityClassName | `""` | +| `metrics.kafka.topologySpreadConstraints` | Topology Spread Constraints for pod assignment | `[]` | +| `metrics.kafka.extraVolumes` | Optionally specify extra list of additional volumes for the Kafka exporter pod(s) | `[]` | +| `metrics.kafka.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the Kafka exporter container(s) | `[]` | +| `metrics.kafka.sidecars` | Add additional sidecar containers to the Kafka exporter pod(s) | `[]` | +| `metrics.kafka.initContainers` | Add init containers to the Kafka exporter pods | `[]` | +| `metrics.kafka.service.ports.metrics` | Kafka exporter metrics service port | `9308` | +| `metrics.kafka.service.clusterIP` | Static clusterIP or None for headless services | `""` | +| `metrics.kafka.service.sessionAffinity` | Control where client requests go, to the same pod or round-robin | `None` | +| `metrics.kafka.service.annotations` | Annotations for the Kafka exporter service | `{}` | +| `metrics.kafka.serviceAccount.create` | Enable creation of ServiceAccount for Kafka exporter pods | `true` | +| `metrics.kafka.serviceAccount.name` | The name of the service account to use. If not set and `create` is `true`, a name is generated | `""` | +| `metrics.kafka.serviceAccount.automountServiceAccountToken` | Allows auto mount of ServiceAccountToken on the serviceAccount created | `true` | +| `metrics.jmx.enabled` | Whether or not to expose JMX metrics to Prometheus | `false` | +| `metrics.jmx.image.registry` | JMX exporter image registry | `docker.io` | +| `metrics.jmx.image.repository` | JMX exporter image repository | `bitnami/jmx-exporter` | +| `metrics.jmx.image.tag` | JMX exporter image tag (immutable tags are recommended) | `0.17.2-debian-11-r29` | +| `metrics.jmx.image.digest` | JMX exporter image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | +| `metrics.jmx.image.pullPolicy` | JMX exporter image pull policy | `IfNotPresent` | +| `metrics.jmx.image.pullSecrets` | Specify docker-registry secret names as an array | `[]` | +| `metrics.jmx.containerSecurityContext.enabled` | Enable Prometheus JMX exporter containers' Security Context | `true` | +| `metrics.jmx.containerSecurityContext.runAsUser` | Set Prometheus JMX exporter containers' Security Context runAsUser | `1001` | +| `metrics.jmx.containerSecurityContext.runAsNonRoot` | Set Prometheus JMX exporter containers' Security Context runAsNonRoot | `true` | +| `metrics.jmx.containerPorts.metrics` | Prometheus JMX exporter metrics container port | `5556` | +| `metrics.jmx.resources.limits` | The resources limits for the JMX exporter container | `{}` | +| `metrics.jmx.resources.requests` | The requested resources for the JMX exporter container | `{}` | +| `metrics.jmx.service.ports.metrics` | Prometheus JMX exporter metrics service port | `5556` | +| `metrics.jmx.service.clusterIP` | Static clusterIP or None for headless services | `""` | +| `metrics.jmx.service.sessionAffinity` | Control where client requests go, to the same pod or round-robin | `None` | +| `metrics.jmx.service.annotations` | Annotations for the Prometheus JMX exporter service | `{}` | +| `metrics.jmx.whitelistObjectNames` | Allows setting which JMX objects you want to expose to via JMX stats to JMX exporter | `["kafka.controller:*","kafka.server:*","java.lang:*","kafka.network:*","kafka.log:*"]` | +| `metrics.jmx.config` | Configuration file for JMX exporter | `""` | +| `metrics.jmx.existingConfigmap` | Name of existing ConfigMap with JMX exporter configuration | `""` | +| `metrics.jmx.extraRules` | Add extra rules to JMX exporter configuration | `""` | +| `metrics.serviceMonitor.enabled` | if `true`, creates a Prometheus Operator ServiceMonitor (requires `metrics.kafka.enabled` or `metrics.jmx.enabled` to be `true`) | `false` | +| `metrics.serviceMonitor.namespace` | Namespace in which Prometheus is running | `""` | +| `metrics.serviceMonitor.interval` | Interval at which metrics should be scraped | `""` | +| `metrics.serviceMonitor.scrapeTimeout` | Timeout after which the scrape is ended | `""` | +| `metrics.serviceMonitor.labels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | `{}` | +| `metrics.serviceMonitor.selector` | Prometheus instance selector labels | `{}` | +| `metrics.serviceMonitor.relabelings` | RelabelConfigs to apply to samples before scraping | `[]` | +| `metrics.serviceMonitor.metricRelabelings` | MetricRelabelConfigs to apply to samples before ingestion | `[]` | +| `metrics.serviceMonitor.honorLabels` | Specify honorLabels parameter to add the scrape endpoint | `false` | +| `metrics.serviceMonitor.jobLabel` | The name of the label on the target service to use as the job name in prometheus. | `""` | +| `metrics.prometheusRule.enabled` | if `true`, creates a Prometheus Operator PrometheusRule (requires `metrics.kafka.enabled` or `metrics.jmx.enabled` to be `true`) | `false` | +| `metrics.prometheusRule.namespace` | Namespace in which Prometheus is running | `""` | +| `metrics.prometheusRule.labels` | Additional labels that can be used so PrometheusRule will be discovered by Prometheus | `{}` | +| `metrics.prometheusRule.groups` | Prometheus Rule Groups for Kafka | `[]` | + + +### Kafka provisioning parameters + +| Name | Description | Value | +| ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | --------------------- | +| `provisioning.enabled` | Enable kafka provisioning Job | `false` | +| `provisioning.numPartitions` | Default number of partitions for topics when unspecified | `1` | +| `provisioning.replicationFactor` | Default replication factor for topics when unspecified | `1` | +| `provisioning.topics` | Kafka topics to provision | `[]` | +| `provisioning.nodeSelector` | Node labels for pod assignment | `{}` | +| `provisioning.tolerations` | Tolerations for pod assignment | `[]` | +| `provisioning.extraProvisioningCommands` | Extra commands to run to provision cluster resources | `[]` | +| `provisioning.parallel` | Number of provisioning commands to run at the same time | `1` | +| `provisioning.preScript` | Extra bash script to run before topic provisioning. $CLIENT_CONF is path to properties file with most needed configurations | `""` | +| `provisioning.postScript` | Extra bash script to run after topic provisioning. $CLIENT_CONF is path to properties file with most needed configurations | `""` | +| `provisioning.auth.tls.type` | Format to use for TLS certificates. Allowed types: `jks` and `pem`. | `jks` | +| `provisioning.auth.tls.certificatesSecret` | Existing secret containing the TLS certificates for the Kafka provisioning Job. | `""` | +| `provisioning.auth.tls.cert` | The secret key from the certificatesSecret if 'cert' key different from the default (tls.crt) | `tls.crt` | +| `provisioning.auth.tls.key` | The secret key from the certificatesSecret if 'key' key different from the default (tls.key) | `tls.key` | +| `provisioning.auth.tls.caCert` | The secret key from the certificatesSecret if 'caCert' key different from the default (ca.crt) | `ca.crt` | +| `provisioning.auth.tls.keystore` | The secret key from the certificatesSecret if 'keystore' key different from the default (keystore.jks) | `keystore.jks` | +| `provisioning.auth.tls.truststore` | The secret key from the certificatesSecret if 'truststore' key different from the default (truststore.jks) | `truststore.jks` | +| `provisioning.auth.tls.passwordsSecret` | Name of the secret containing passwords to access the JKS files or PEM key when they are password-protected. | `""` | +| `provisioning.auth.tls.keyPasswordSecretKey` | The secret key from the passwordsSecret if 'keyPasswordSecretKey' key different from the default (key-password) | `key-password` | +| `provisioning.auth.tls.keystorePasswordSecretKey` | The secret key from the passwordsSecret if 'keystorePasswordSecretKey' key different from the default (keystore-password) | `keystore-password` | +| `provisioning.auth.tls.truststorePasswordSecretKey` | The secret key from the passwordsSecret if 'truststorePasswordSecretKey' key different from the default (truststore-password) | `truststore-password` | +| `provisioning.auth.tls.keyPassword` | Password to access the password-protected PEM key if necessary. Ignored if 'passwordsSecret' is provided. | `""` | +| `provisioning.auth.tls.keystorePassword` | Password to access the JKS keystore. Ignored if 'passwordsSecret' is provided. | `""` | +| `provisioning.auth.tls.truststorePassword` | Password to access the JKS truststore. Ignored if 'passwordsSecret' is provided. | `""` | +| `provisioning.command` | Override provisioning container command | `[]` | +| `provisioning.args` | Override provisioning container arguments | `[]` | +| `provisioning.extraEnvVars` | Extra environment variables to add to the provisioning pod | `[]` | +| `provisioning.extraEnvVarsCM` | ConfigMap with extra environment variables | `""` | +| `provisioning.extraEnvVarsSecret` | Secret with extra environment variables | `""` | +| `provisioning.podAnnotations` | Extra annotations for Kafka provisioning pods | `{}` | +| `provisioning.podLabels` | Extra labels for Kafka provisioning pods | `{}` | +| `provisioning.serviceAccount.create` | Enable creation of ServiceAccount for Kafka provisioning pods | `false` | +| `provisioning.serviceAccount.name` | The name of the service account to use. If not set and `create` is `true`, a name is generated | `""` | +| `provisioning.serviceAccount.automountServiceAccountToken` | Allows auto mount of ServiceAccountToken on the serviceAccount created | `true` | +| `provisioning.resources.limits` | The resources limits for the Kafka provisioning container | `{}` | +| `provisioning.resources.requests` | The requested resources for the Kafka provisioning container | `{}` | +| `provisioning.podSecurityContext.enabled` | Enable security context for the pods | `true` | +| `provisioning.podSecurityContext.fsGroup` | Set Kafka provisioning pod's Security Context fsGroup | `1001` | +| `provisioning.containerSecurityContext.enabled` | Enable Kafka provisioning containers' Security Context | `true` | +| `provisioning.containerSecurityContext.runAsUser` | Set Kafka provisioning containers' Security Context runAsUser | `1001` | +| `provisioning.containerSecurityContext.runAsNonRoot` | Set Kafka provisioning containers' Security Context runAsNonRoot | `true` | +| `provisioning.schedulerName` | Name of the k8s scheduler (other than default) for kafka provisioning | `""` | +| `provisioning.extraVolumes` | Optionally specify extra list of additional volumes for the Kafka provisioning pod(s) | `[]` | +| `provisioning.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the Kafka provisioning container(s) | `[]` | +| `provisioning.sidecars` | Add additional sidecar containers to the Kafka provisioning pod(s) | `[]` | +| `provisioning.initContainers` | Add additional Add init containers to the Kafka provisioning pod(s) | `[]` | +| `provisioning.waitForKafka` | If true use an init container to wait until kafka is ready before starting provisioning | `true` | + + +### ZooKeeper chart parameters + +| Name | Description | Value | +| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | +| `zookeeper.enabled` | Switch to enable or disable the ZooKeeper helm chart | `true` | +| `zookeeper.replicaCount` | Number of ZooKeeper nodes | `1` | +| `zookeeper.auth.client.enabled` | Enable ZooKeeper auth | `false` | +| `zookeeper.auth.client.clientUser` | User that will use ZooKeeper clients to auth | `""` | +| `zookeeper.auth.client.clientPassword` | Password that will use ZooKeeper clients to auth | `""` | +| `zookeeper.auth.client.serverUsers` | Comma, semicolon or whitespace separated list of user to be created. Specify them as a string, for example: "user1,user2,admin" | `""` | +| `zookeeper.auth.client.serverPasswords` | Comma, semicolon or whitespace separated list of passwords to assign to users when created. Specify them as a string, for example: "pass4user1, pass4user2, pass4admin" | `""` | +| `zookeeper.persistence.enabled` | Enable persistence on ZooKeeper using PVC(s) | `true` | +| `zookeeper.persistence.storageClass` | Persistent Volume storage class | `""` | +| `zookeeper.persistence.accessModes` | Persistent Volume access modes | `["ReadWriteOnce"]` | +| `zookeeper.persistence.size` | Persistent Volume size | `8Gi` | +| `externalZookeeper.servers` | List of external zookeeper servers to use. Typically used in combination with 'zookeeperChrootPath'. | `[]` | + + +Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +helm install my-release \ + --set replicaCount=3 \ + my-repo/kafka +``` + +The above command deploys Kafka with 3 brokers (replicas). + +Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, + +```console +helm install my-release -f values.yaml my-repo/kafka +``` + +> **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. + +### Setting custom parameters + +Any environment variable beginning with `KAFKA_CFG_` will be mapped to its corresponding Kafka key. For example, use `KAFKA_CFG_BACKGROUND_THREADS` in order to set `background.threads`. In order to pass custom environment variables use the `extraEnvVars` property. + +Using `extraEnvVars` with `KAFKA_CFG_` is the preferred and simplest way to add custom Kafka parameters not otherwise specified in this chart. Alternatively, you can provide a *full* Kafka configuration using `config` or `existingConfigmap`. +Setting either `config` or `existingConfigmap` will cause the chart to disregard `KAFKA_CFG_` settings, which are used by many other Kafka-related chart values described above, as well as dynamically generated parameters such as `zookeeper.connect`. This can cause unexpected behavior. + +### Listeners configuration + +This chart allows you to automatically configure Kafka with 3 listeners: + +- One for inter-broker communications. +- A second one for communications with clients within the K8s cluster. +- (optional) a third listener for communications with clients outside the K8s cluster. Check [this section](#accessing-kafka-brokers-from-outside-the-cluster) for more information. + +For more complex configurations, set the `listeners`, `advertisedListeners` and `listenerSecurityProtocolMap` parameters as needed. + +### Enable security for Kafka and Zookeeper + +You can configure different authentication protocols for each listener you configure in Kafka. For instance, you can use `sasl_tls` authentication for client communications, while using `tls` for inter-broker communications. This table shows the available protocols and the security they provide: + +| Method | Authentication | Encryption via TLS | +|-----------|------------------------------|--------------------| +| plaintext | None | No | +| tls | None | Yes | +| mtls | Yes (two-way authentication) | Yes | +| sasl | Yes (via SASL) | No | +| sasl_tls | Yes (via SASL) | Yes | + +Learn more about how to configure Kafka to use the different authentication protocols in the [chart documentation](https://docs.bitnami.com/kubernetes/infrastructure/kafka/administration/enable-security/). + +If you enabled SASL authentication on any listener, you can set the SASL credentials using the parameters below: + +- `auth.sasl.jaas.clientUsers`/`auth.sasl.jaas.clientPasswords`: when enabling SASL authentication for communications with clients. +- `auth.sasl.jaas.interBrokerUser`/`auth.sasl.jaas.interBrokerPassword`: when enabling SASL authentication for inter-broker communications. +- `auth.jaas.zookeeperUser`/`auth.jaas.zookeeperPassword`: In the case that the Zookeeper chart is deployed with SASL authentication enabled. + +In order to configure TLS authentication/encryption, you **can** create a secret per Kafka broker you have in the cluster containing the Java Key Stores (JKS) files: the truststore (`kafka.truststore.jks`) and the keystore (`kafka.keystore.jks`). Then, you need pass the secret names with the `auth.tls.existingSecrets` parameter when deploying the chart. + +> **Note**: If the JKS files are password protected (recommended), you will need to provide the password to get access to the keystores. To do so, use the `auth.tls.password` parameter to provide your password. + +For instance, to configure TLS authentication on a Kafka cluster with 2 Kafka brokers use the commands below to create the secrets: + +```console +kubectl create secret generic kafka-jks-0 --from-file=kafka.truststore.jks=./kafka.truststore.jks --from-file=kafka.keystore.jks=./kafka-0.keystore.jks +kubectl create secret generic kafka-jks-1 --from-file=kafka.truststore.jks=./kafka.truststore.jks --from-file=kafka.keystore.jks=./kafka-1.keystore.jks +``` + +> **Note**: the command above assumes you already created the truststore and keystores files. This [script](https://raw.githubusercontent.com/confluentinc/confluent-platform-security-tools/master/kafka-generate-ssl.sh) can help you with the JKS files generation. + +If, for some reason (like using Cert-Manager) you can not use the default JKS secret scheme, you can use the additional parameters: + +- `auth.tls.jksTruststoreSecret` to define additional secret, where the `kafka.truststore.jks` is being kept. The truststore password **must** be the same as in `auth.tls.password` +- `auth.tls.jksTruststore` to overwrite the default value of the truststore key (`kafka.truststore.jks`). +- `auth.tls.jksKeystoreSAN` if you want to use a SAN certificate for your brokers. Setting this parameter would mean that the chart expects a existing key in the `auth.tls.jksTruststoreSecret` with the `auth.tls.jksKeystoreSAN` value and use this as a keystore for **all** brokers +> **Note**: If you are using cert-manager, particularly when an ACME issuer is used, the `ca.crt` field is not put in the `Secret` that cert-manager creates. To handle this, the `auth.tls.pemChainIncluded` property can be set to `true` and the initContainer created by this Chart will attempt to extract the intermediate certs from the `tls.crt` field of the secret (which is a PEM chain) + +> **Note**: The truststore/keystore from above **must** be protected with the same password as in `auth.tls.password` + +You can deploy the chart with authentication using the following parameters: + +```console +replicaCount=2 +auth.clientProtocol=sasl +auth.interBrokerProtocol=tls +auth.tls.existingSecrets[0]=kafka-jks-0 +auth.tls.existingSecrets[1]=kafka-jks-1 +auth.tls.password=jksPassword +auth.sasl.jaas.clientUsers[0]=brokerUser +auth.sasl.jaas.clientPasswords[0]=brokerPassword +auth.sasl.jaas.zookeeperUser=zookeeperUser +auth.sasl.jaas.zookeeperPassword=zookeeperPassword +zookeeper.auth.enabled=true +zookeeper.auth.serverUsers=zookeeperUser +zookeeper.auth.serverPasswords=zookeeperPassword +zookeeper.auth.clientUser=zookeeperUser +zookeeper.auth.clientPassword=zookeeperPassword +``` + +You can deploy the chart with AclAuthorizer using the following parameters: + +```console +replicaCount=2 +auth.clientProtocol=sasl +auth.interBrokerProtocol=sasl_tls +auth.tls.existingSecrets[0]=kafka-jks-0 +auth.tls.existingSecrets[1]=kafka-jks-1 +auth.tls.password=jksPassword +auth.sasl.jaas.clientUsers[0]=brokerUser +auth.sasl.jaas.clientPasswords[0]=brokerPassword +auth.sasl.jaas.zookeeperUser=zookeeperUser +auth.sasl.jaas.zookeeperPassword=zookeeperPassword +zookeeper.auth.enabled=true +zookeeper.auth.serverUsers=zookeeperUser +zookeeper.auth.serverPasswords=zookeeperPassword +zookeeper.auth.clientUser=zookeeperUser +zookeeper.auth.clientPassword=zookeeperPassword +authorizerClassName=kafka.security.authorizer.AclAuthorizer +allowEveryoneIfNoAclFound=false +superUsers=User:admin +``` + +If you are using Kafka ACLs, you might encounter in kafka-authorizer.log the following event: `[...] Principal = User:ANONYMOUS is Allowed Operation [...]`. + +By setting the following parameter: `auth.clientProtocol=mtls`, it will set the configuration in Kafka to `ssl.client.auth=required`. This option will require the clients to authenticate to Kafka brokers. + +As result, we will be able to see in kafka-authorizer.log the events specific Subject: `[...] Principal = User:CN=kafka,OU=...,O=...,L=...,C=..,ST=... is [...]`. + +If you also enable exposing metrics using the Kafka exporter, and you are using `sasl_tls`, `tls`, or `mtls` authentication protocols, you need to mount the CA certificated used to sign the brokers certificates in the exporter so it can validate the Kafka brokers. To do so, create a secret containing the CA, and set the `metrics.certificatesSecret` parameter. As an alternative, you can skip TLS validation using extra flags: + +```console +metrics.kafka.extraFlags={tls.insecure-skip-tls-verify: ""} +``` + +### Accessing Kafka brokers from outside the cluster + +In order to access Kafka Brokers from outside the cluster, an additional listener and advertised listener must be configured. Additionally, a specific service per kafka pod will be created. + +There are three ways of configuring external access. Using LoadBalancer services, using NodePort services or using ClusterIP services. + +#### Using LoadBalancer services + +You have two alternatives to use LoadBalancer services: + +- Option A) Use random load balancer IPs using an **initContainer** that waits for the IPs to be ready and discover them automatically. + +```console +externalAccess.enabled=true +externalAccess.service.type=LoadBalancer +externalAccess.service.ports.external=9094 +externalAccess.autoDiscovery.enabled=true +serviceAccount.create=true +rbac.create=true +``` + +Note: This option requires creating RBAC rules on clusters where RBAC policies are enabled. + +- Option B) Manually specify the load balancer IPs: + +```console +externalAccess.enabled=true +externalAccess.service.type=LoadBalancer +externalAccess.service.ports.external=9094 +externalAccess.service.loadBalancerIPs[0]='external-ip-1' +externalAccess.service.loadBalancerIPs[1]='external-ip-2'} +``` + +Note: You need to know in advance the load balancer IPs so each Kafka broker advertised listener is configured with it. + +Following the aforementioned steps will also allow to connect the brokers from the outside using the cluster's default service (when `service.type` is `LoadBalancer` or `NodePort`). Use the property `service.externalPort` to specify the port used for external connections. + +#### Using NodePort services + +You have two alternatives to use NodePort services: + +- Option A) Use random node ports using an **initContainer** that discover them automatically. + +```console +externalAccess.enabled=true +externalAccess.service.type=NodePort +externalAccess.autoDiscovery.enabled=true +serviceAccount.create=true +rbac.create=true +``` + +Note: This option requires creating RBAC rules on clusters where RBAC policies are enabled. + +- Option B) Manually specify the node ports: + +```console +externalAccess.enabled=true +externalAccess.service.type=NodePort +externalAccess.service.nodePorts[0]='node-port-1' +externalAccess.service.nodePorts[1]='node-port-2' +``` + +Note: You need to know in advance the node ports that will be exposed so each Kafka broker advertised listener is configured with it. + +The pod will try to get the external ip of the node using `curl -s https://ipinfo.io/ip` unless `externalAccess.service.domain` or `externalAccess.service.useHostIPs` is provided. + +#### Using ClusterIP services + +Note: This option requires that an ingress is deployed within your cluster + +```console +externalAccess.enabled=true +externalAccess.service.type=ClusterIP +externalAccess.service.ports.external=9094 +externalAccess.service.domain='ingress-ip' +``` + +Note: the deployed ingress must contain the following block: + +```console +tcp: + 9094: "{{ .Release.Namespace }}/{{ include "kafka.fullname" . }}-0-external:9094" + 9095: "{{ .Release.Namespace }}/{{ include "kafka.fullname" . }}-1-external:9094" + 9096: "{{ .Release.Namespace }}/{{ include "kafka.fullname" . }}-2-external:9094" +``` + +#### Name resolution with External-DNS + +You can use the following values to generate External-DNS annotations which automatically creates DNS records for each ReplicaSet pod: + +```yaml +externalAccess: + service: + annotations: + external-dns.alpha.kubernetes.io/hostname: "{{ .targetPod }}.example.com" +``` + +### Sidecars + +If you have a need for additional containers to run within the same pod as Kafka (e.g. an additional metrics or logging exporter), you can do so via the `sidecars` config parameter. Simply define your container according to the Kubernetes container spec. + +```yaml +sidecars: + - name: your-image-name + image: your-image + imagePullPolicy: Always + ports: + - name: portname + containerPort: 1234 +``` + +### Setting Pod's affinity + +This chart allows you to set your custom affinity using the `affinity` parameter. Find more information about Pod's affinity in the [kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity). + +As an alternative, you can use of the preset configurations for pod affinity, pod anti-affinity, and node affinity available at the [bitnami/common](https://github.com/bitnami/charts/tree/main/bitnami/common#affinities) chart. To do so, set the `podAffinityPreset`, `podAntiAffinityPreset`, or `nodeAffinityPreset` parameters. + +### Deploying extra resources + +There are cases where you may want to deploy extra objects, such as Kafka Connect. For covering this case, the chart allows adding the full specification of other objects using the `extraDeploy` parameter. The following example would create a deployment including a Kafka Connect deployment so you can connect Kafka with MongoDB®: + +```yaml +## Extra objects to deploy (value evaluated as a template) +## +extraDeploy: + - | + apiVersion: apps/v1 + kind: Deployment + metadata: + name: {{ include "kafka.fullname" . }}-connect + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: connector + spec: + replicas: 1 + selector: + matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: connector + template: + metadata: + labels: {{- include "common.labels.standard" . | nindent 8 }} + app.kubernetes.io/component: connector + spec: + containers: + - name: connect + image: KAFKA-CONNECT-IMAGE + imagePullPolicy: IfNotPresent + ports: + - name: connector + containerPort: 8083 + volumeMounts: + - name: configuration + mountPath: /bitnami/kafka/config + volumes: + - name: configuration + configMap: + name: {{ include "kafka.fullname" . }}-connect + - | + apiVersion: v1 + kind: ConfigMap + metadata: + name: {{ include "kafka.fullname" . }}-connect + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: connector + data: + connect-standalone.properties: |- + bootstrap.servers = {{ include "kafka.fullname" . }}-0.{{ include "kafka.fullname" . }}-headless.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }}:{{ .Values.service.port }} + ... + mongodb.properties: |- + connection.uri=mongodb://root:password@mongodb-hostname:27017 + ... + - | + apiVersion: v1 + kind: Service + metadata: + name: {{ include "kafka.fullname" . }}-connect + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: connector + spec: + ports: + - protocol: TCP + port: 8083 + targetPort: connector + selector: {{- include "common.labels.matchLabels" . | nindent 4 }} + app.kubernetes.io/component: connector +``` + +You can create the Kafka Connect image using the Dockerfile below: + +```Dockerfile +FROM bitnami/kafka:latest +# Download MongoDB® Connector for Apache Kafka https://www.confluent.io/hub/mongodb/kafka-connect-mongodb +RUN mkdir -p /opt/bitnami/kafka/plugins && \ + cd /opt/bitnami/kafka/plugins && \ + curl --remote-name --location --silent https://search.maven.org/remotecontent?filepath=org/mongodb/kafka/mongo-kafka-connect/1.2.0/mongo-kafka-connect-1.2.0-all.jar +CMD /opt/bitnami/kafka/bin/connect-standalone.sh /opt/bitnami/kafka/config/connect-standalone.properties /opt/bitnami/kafka/config/mongo.properties +``` + +## Persistence + +The [Bitnami Kafka](https://github.com/bitnami/containers/tree/main/bitnami/kafka) image stores the Kafka data at the `/bitnami/kafka` path of the container. + +Persistent Volume Claims are used to keep the data across deployments. This is known to work in GCE, AWS, and minikube. See the [Parameters](#persistence-parameters) section to configure the PVC or to disable persistence. + +### 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 + +### To 20.0.0 + +This major updates the Zookeeper subchart to it newest major, 11.0.0. For more information on this subchart's major, please refer to [zookeeper upgrade notes](https://github.com/bitnami/charts/tree/main/bitnami/zookeeper#to-1100). + +### To 19.0.0 + +This major updates Kafka to its newest version, 3.3.x. For more information, please refer to [kafka upgrade notes](https://kafka.apache.org/33/documentation.html#upgrade). + +### To 18.0.0 + +This major updates the Zookeeper subchart to it newest major, 10.0.0. For more information on this subchart's major, please refer to [zookeeper upgrade notes](https://github.com/bitnami/charts/tree/main/bitnami/zookeeper#to-1000). + +### To 16.0.0 + +This major updates the Zookeeper subchart to it newest major, 9.0.0. For more information on this subchart's major, please refer to [zookeeper upgrade notes](https://github.com/bitnami/charts/tree/main/bitnami/zookeeper#to-900). + +### To 15.0.0 + +This major release bumps Kafka major version to `3.x` series. +It also 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. Some affected values are: + +- `service.port`, `service.internalPort` and `service.externalPort` have been regrouped under the `service.ports` map. +- `metrics.kafka.service.port` has been regrouped under the `metrics.kafka.service.ports` map. +- `metrics.jmx.service.port` has been regrouped under the `metrics.jmx.service.ports` map. +- `updateStrategy` (string) and `rollingUpdatePartition` are regrouped under the `updateStrategy` map. +- Several parameters marked as deprecated `14.x.x` are not supported anymore. + +Additionally updates the ZooKeeper subchart to it newest major, `8.0.0`, which contains similar changes. + +### To 14.0.0 + +In this version, the `image` block is defined once and is used in the different templates, while in the previous version, the `image` block was duplicated for the main container and the provisioning one + +```yaml +image: + registry: docker.io + repository: bitnami/kafka + tag: 2.8.0 +``` + +VS + +```yaml +image: + registry: docker.io + repository: bitnami/kafka + tag: 2.8.0 +... +provisioning: + image: + registry: docker.io + repository: bitnami/kafka + tag: 2.8.0 +``` + +See [PR#7114](https://github.com/bitnami/charts/pull/7114) for more info about the implemented changes + +### To 13.0.0 + +This major updates the Zookeeper subchart to it newest major, 7.0.0, which renames all TLS-related settings. For more information on this subchart's major, please refer to [zookeeper upgrade notes](https://github.com/bitnami/charts/tree/main/bitnami/zookeeper#to-700). + +### To 12.2.0 + +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. + +### To 12.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. +- Move dependency information from the *requirements.yaml* to the *Chart.yaml* +- After running `helm dependency update`, a *Chart.lock* file is generated containing the same structure used in the previous *requirements.lock* +- 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/ + +### To 11.8.0 + +External access to brokers can now be achieved through the cluster's Kafka service. + +- `service.nodePort` -> deprecated in favor of `service.nodePorts.client` and `service.nodePorts.external` + +### To 11.7.0 + +The way to configure the users and passwords changed. Now it is allowed to create multiple users during the installation by providing the list of users and passwords. + +- `auth.jaas.clientUser` (string) -> deprecated in favor of `auth.jaas.clientUsers` (array). +- `auth.jaas.clientPassword` (string) -> deprecated in favor of `auth.jaas.clientPasswords` (array). + +### To 11.0.0 + +The way to configure listeners and athentication on Kafka is totally refactored allowing users to configure different authentication protocols on different listeners. Please check the [Listeners Configuration](#listeners-configuration) section for more information. + +Backwards compatibility is not guaranteed you adapt your values.yaml to the new format. Here you can find some parameters that were renamed or disappeared in favor of new ones on this major version: + +- `auth.enabled` -> deprecated in favor of `auth.clientProtocol` and `auth.interBrokerProtocol` parameters. +- `auth.ssl` -> deprecated in favor of `auth.clientProtocol` and `auth.interBrokerProtocol` parameters. +- `auth.certificatesSecret` -> renamed to `auth.jksSecret`. +- `auth.certificatesPassword` -> renamed to `auth.jksPassword`. +- `sslEndpointIdentificationAlgorithm` -> renamedo to `auth.tlsEndpointIdentificationAlgorithm`. +- `auth.interBrokerUser` -> renamed to `auth.jaas.interBrokerUser` +- `auth.interBrokerPassword` -> renamed to `auth.jaas.interBrokerPassword` +- `auth.zookeeperUser` -> renamed to `auth.jaas.zookeeperUser` +- `auth.zookeeperPassword` -> renamed to `auth.jaas.zookeeperPassword` +- `auth.existingSecret` -> renamed to `auth.jaas.existingSecret` +- `service.sslPort` -> deprecated in favor of `service.internalPort` +- `service.nodePorts.kafka` and `service.nodePorts.ssl` -> deprecated in favor of `service.nodePort` +- `metrics.kafka.extraFlag` -> new parameter +- `metrics.kafka.certificatesSecret` -> new parameter + +### To 10.0.0 + +If you are setting the `config` or `log4j` parameter, backwards compatibility is not guaranteed, because the `KAFKA_MOUNTED_CONFDIR` has moved from `/opt/bitnami/kafka/conf` to `/bitnami/kafka/config`. In order to continue using these parameters, you must also upgrade your image to `docker.io/bitnami/kafka:2.4.1-debian-10-r38` or later. + +### To 9.0.0 + +Backwards compatibility is not guaranteed you adapt your values.yaml to the new format. Here you can find some parameters that were renamed on this major version: + +```diff +- securityContext.enabled +- securityContext.fsGroup +- securityContext.fsGroup ++ podSecurityContext +- externalAccess.service.loadBalancerIP ++ externalAccess.service.loadBalancerIPs +- externalAccess.service.nodePort ++ externalAccess.service.nodePorts +- metrics.jmx.configMap.enabled +- metrics.jmx.configMap.overrideConfig ++ metrics.jmx.config +- metrics.jmx.configMap.overrideName ++ metrics.jmx.existingConfigmap +``` + +Ports names were prefixed with the protocol to comply with Istio (see https://istio.io/docs/ops/deployment/requirements/). + +### To 8.0.0 + +There is not backwards compatibility since the brokerID changes to the POD_NAME. For more information see [this PR](https://github.com/bitnami/charts/pull/2028). + +### To 7.0.0 + +Backwards compatibility is not guaranteed when Kafka metrics are enabled, unless you modify the labels used on the exporter deployments. +Use the workaround below to upgrade from versions previous to 7.0.0. The following example assumes that the release name is kafka: + +```console +helm upgrade kafka my-repo/kafka --version 6.1.8 --set metrics.kafka.enabled=false +helm upgrade kafka my-repo/kafka --version 7.0.0 --set metrics.kafka.enabled=true +``` + +### To 2.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 2.0.0. The following example assumes that the release name is kafka: + +```console +kubectl delete statefulset kafka-kafka --cascade=false +kubectl delete statefulset kafka-zookeeper --cascade=false +``` + +### To 1.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 1.0.0. The following example assumes that the release name is kafka: + +```console +kubectl delete statefulset kafka-kafka --cascade=false +kubectl delete statefulset kafka-zookeeper --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/deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/.helmignore b/deployment/charts/kafka/charts/common/.helmignore similarity index 100% rename from deployment/deployment/middleware_deployment/elasticsearch/charts/kibana/charts/common/.helmignore rename to deployment/charts/kafka/charts/common/.helmignore diff --git a/deployment/deployment/nginx-ingress-controller/charts/common/Chart.yaml b/deployment/charts/kafka/charts/common/Chart.yaml similarity index 67% rename from deployment/deployment/nginx-ingress-controller/charts/common/Chart.yaml rename to deployment/charts/kafka/charts/common/Chart.yaml index 5264c47..f9ba944 100644 --- a/deployment/deployment/nginx-ingress-controller/charts/common/Chart.yaml +++ b/deployment/charts/kafka/charts/common/Chart.yaml @@ -1,10 +1,10 @@ annotations: category: Infrastructure apiVersion: v2 -appVersion: 1.10.0 +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/master/bitnami/common +home: https://github.com/bitnami/charts/tree/main/bitnami/common icon: https://bitnami.com/downloads/logos/bitnami-mark.png keywords: - common @@ -13,11 +13,11 @@ keywords: - function - bitnami maintainers: -- email: containers@bitnami.com - name: Bitnami +- name: Bitnami + url: https://github.com/bitnami/charts name: common sources: - https://github.com/bitnami/charts -- http://www.bitnami.com/ +- https://www.bitnami.com/ type: library -version: 1.10.1 +version: 2.2.2 diff --git a/deployment/deployment/nginx-ingress-controller/charts/common/README.md b/deployment/charts/kafka/charts/common/README.md similarity index 72% rename from deployment/deployment/nginx-ingress-controller/charts/common/README.md rename to deployment/charts/kafka/charts/common/README.md index cbbc31d..ec43a5f 100644 --- a/deployment/deployment/nginx-ingress-controller/charts/common/README.md +++ b/deployment/charts/kafka/charts/common/README.md @@ -7,7 +7,7 @@ A [Helm Library Chart](https://helm.sh/docs/topics/library_charts/#helm) for gro ```yaml dependencies: - name: common - version: 0.x.x + version: 1.x.x repository: https://charts.bitnami.com/bitnami ``` @@ -28,12 +28,12 @@ data: 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.com/) for deployment and management of Helm Charts in clusters. This Helm chart has been tested on top of [Bitnami Kubernetes Production Runtime](https://kubeprod.io/) (BKPR). Deploy BKPR to get automated TLS certificates, logging and monitoring for your applications. +Bitnami charts can be used with [Kubeapps](https://kubeapps.dev/) for deployment and management of Helm Charts in clusters. ## Prerequisites -- Kubernetes 1.12+ -- Helm 3.1.0 +- Kubernetes 1.19+ +- Helm 3.2.0+ ## Parameters @@ -43,10 +43,11 @@ The following table lists the helpers available in the library which are scoped | Helper identifier | Description | Expected Input | |-------------------------------|------------------------------------------------------|------------------------------------------------| -| `common.affinities.node.soft` | Return a soft nodeAffinity definition | `dict "key" "FOO" "values" (list "BAR" "BAZ")` | -| `common.affinities.node.hard` | Return a hard nodeAffinity definition | `dict "key" "FOO" "values" (list "BAR" "BAZ")` | -| `common.affinities.pod.soft` | Return a soft podAffinity/podAntiAffinity definition | `dict "component" "FOO" "context" $` | -| `common.affinities.pod.hard` | Return a hard podAffinity/podAntiAffinity definition | `dict "component" "FOO" "context" $` | +| `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 @@ -61,6 +62,8 @@ The following table lists the helpers available in the library which are scoped | `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 @@ -79,35 +82,38 @@ The following table lists the helpers available in the library which are scoped ### 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 | +| 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` | Return the proper Docker Image Registry Secret Names | `.` Chart context | +| 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.chart` | Chart name plus version | `.` Chart context | +| 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.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" $` | +| 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 @@ -137,8 +143,9 @@ The following table lists the helpers available in the library which are scoped | `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.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. | @@ -296,11 +303,11 @@ If we force those values to be empty we will see some alerts $ 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 --decode) + 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 --decode) + export PASSWORD_01=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-01}" | base64 -d) ``` ## Upgrading @@ -326,3 +333,19 @@ $ helm install test mychart --set path.to.value00="",path.to.value01="" - 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/deployment/deployment/nginx-ingress-controller/charts/common/templates/_affinities.tpl b/deployment/charts/kafka/charts/common/templates/_affinities.tpl similarity index 83% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/_affinities.tpl rename to deployment/charts/kafka/charts/common/templates/_affinities.tpl index 189ea40..81902a6 100644 --- a/deployment/deployment/nginx-ingress-controller/charts/common/templates/_affinities.tpl +++ b/deployment/charts/kafka/charts/common/templates/_affinities.tpl @@ -1,7 +1,7 @@ {{/* vim: set filetype=mustache: */}} {{/* -Return a soft nodeAffinity definition +Return a soft nodeAffinity definition {{ include "common.affinities.nodes.soft" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}} */}} {{- define "common.affinities.nodes.soft" -}} @@ -45,9 +45,17 @@ Return a nodeAffinity definition {{- 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 "context" $) -}} +{{ include "common.affinities.pods.soft" (dict "component" "FOO" "extraMatchLabels" .Values.extraMatchLabels "topologyKey" "BAR" "context" $) -}} */}} {{- define "common.affinities.pods.soft" -}} {{- $component := default "" .component -}} @@ -62,15 +70,13 @@ preferredDuringSchedulingIgnoredDuringExecution: {{- range $key, $value := $extraMatchLabels }} {{ $key }}: {{ $value | quote }} {{- end }} - namespaces: - - {{ .context.Release.Namespace | quote }} - topologyKey: kubernetes.io/hostname + 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 "context" $) -}} +{{ include "common.affinities.pods.hard" (dict "component" "FOO" "extraMatchLabels" .Values.extraMatchLabels "topologyKey" "BAR" "context" $) -}} */}} {{- define "common.affinities.pods.hard" -}} {{- $component := default "" .component -}} @@ -84,9 +90,7 @@ requiredDuringSchedulingIgnoredDuringExecution: {{- range $key, $value := $extraMatchLabels }} {{ $key }}: {{ $value | quote }} {{- end }} - namespaces: - - {{ .context.Release.Namespace | quote }} - topologyKey: kubernetes.io/hostname + topologyKey: {{ include "common.affinities.topologyKey" (dict "topologyKey" .topologyKey) }} {{- end -}} {{/* diff --git a/deployment/deployment/nginx-ingress-controller/charts/common/templates/_capabilities.tpl b/deployment/charts/kafka/charts/common/templates/_capabilities.tpl similarity index 83% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/_capabilities.tpl rename to deployment/charts/kafka/charts/common/templates/_capabilities.tpl index 58beacb..9d9b760 100644 --- a/deployment/deployment/nginx-ingress-controller/charts/common/templates/_capabilities.tpl +++ b/deployment/charts/kafka/charts/common/templates/_capabilities.tpl @@ -80,14 +80,14 @@ Return the appropriate apiVersion for ingress. {{- 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/v1" -}} +{{- 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/v1" -}} +{{- print "networking.k8s.io/v1beta1" -}} {{- else -}} {{- print "networking.k8s.io/v1" -}} {{- end -}} @@ -115,6 +115,32 @@ Return the appropriate apiVersion for CRDs. {{- 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. diff --git a/deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/_errors.tpl b/deployment/charts/kafka/charts/common/templates/_errors.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/_errors.tpl rename to deployment/charts/kafka/charts/common/templates/_errors.tpl diff --git a/deployment/deployment/nginx-ingress-controller/charts/common/templates/_images.tpl b/deployment/charts/kafka/charts/common/templates/_images.tpl similarity index 88% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/_images.tpl rename to deployment/charts/kafka/charts/common/templates/_images.tpl index 42ffbc7..46c659e 100644 --- a/deployment/deployment/nginx-ingress-controller/charts/common/templates/_images.tpl +++ b/deployment/charts/kafka/charts/common/templates/_images.tpl @@ -6,17 +6,18 @@ Return the proper image name {{- define "common.images.image" -}} {{- $registryName := .imageRoot.registry -}} {{- $repositoryName := .imageRoot.repository -}} -{{- $tag := .imageRoot.tag | toString -}} +{{- $separator := ":" -}} +{{- $termination := .imageRoot.tag | toString -}} {{- if .global }} {{- if .global.imageRegistry }} {{- $registryName = .global.imageRegistry -}} {{- end -}} {{- end -}} -{{- if $registryName }} -{{- printf "%s/%s:%s" $registryName $repositoryName $tag -}} -{{- else -}} -{{- printf "%s:%s" $repositoryName $tag -}} +{{- if .imageRoot.digest }} + {{- $separator = "@" -}} + {{- $termination = .imageRoot.digest | toString -}} {{- end -}} +{{- printf "%s/%s%s%s" $registryName $repositoryName $separator $termination -}} {{- end -}} {{/* diff --git a/deployment/deployment/nginx-ingress-controller/charts/common/templates/_ingress.tpl b/deployment/charts/kafka/charts/common/templates/_ingress.tpl similarity index 74% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/_ingress.tpl rename to deployment/charts/kafka/charts/common/templates/_ingress.tpl index 7da5ce5..831da9c 100644 --- a/deployment/deployment/nginx-ingress-controller/charts/common/templates/_ingress.tpl +++ b/deployment/charts/kafka/charts/common/templates/_ingress.tpl @@ -13,7 +13,7 @@ Params: */}} {{- define "common.ingress.backend" -}} {{- $apiVersion := (include "common.capabilities.ingress.apiVersion" .context) -}} -{{- if or (eq $apiVersion "extensions/v1beta1") (eq $apiVersion "networking.k8s.io/v1") -}} +{{- if or (eq $apiVersion "extensions/v1beta1") (eq $apiVersion "networking.k8s.io/v1beta1") -}} serviceName: {{ .serviceName }} servicePort: {{ .servicePort }} {{- else -}} @@ -53,3 +53,16 @@ Usage: {{- 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/deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/_labels.tpl b/deployment/charts/kafka/charts/common/templates/_labels.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/_labels.tpl rename to deployment/charts/kafka/charts/common/templates/_labels.tpl diff --git a/deployment/deployment/nginx-ingress-controller/charts/common/templates/_names.tpl b/deployment/charts/kafka/charts/common/templates/_names.tpl similarity index 78% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/_names.tpl rename to deployment/charts/kafka/charts/common/templates/_names.tpl index cf03231..617a234 100644 --- a/deployment/deployment/nginx-ingress-controller/charts/common/templates/_names.tpl +++ b/deployment/charts/kafka/charts/common/templates/_names.tpl @@ -50,3 +50,17 @@ Usage: {{- 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/deployment/charts/kafka/charts/common/templates/_secrets.tpl b/deployment/charts/kafka/charts/common/templates/_secrets.tpl new file mode 100644 index 0000000..a1708b2 --- /dev/null +++ b/deployment/charts/kafka/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/deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/_storage.tpl b/deployment/charts/kafka/charts/common/templates/_storage.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/_storage.tpl rename to deployment/charts/kafka/charts/common/templates/_storage.tpl diff --git a/deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/_tplvalues.tpl b/deployment/charts/kafka/charts/common/templates/_tplvalues.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/_tplvalues.tpl rename to deployment/charts/kafka/charts/common/templates/_tplvalues.tpl diff --git a/deployment/charts/kafka/charts/common/templates/_utils.tpl b/deployment/charts/kafka/charts/common/templates/_utils.tpl new file mode 100644 index 0000000..b1ead50 --- /dev/null +++ b/deployment/charts/kafka/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/deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/_warnings.tpl b/deployment/charts/kafka/charts/common/templates/_warnings.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/_warnings.tpl rename to deployment/charts/kafka/charts/common/templates/_warnings.tpl diff --git a/deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/validations/_cassandra.tpl b/deployment/charts/kafka/charts/common/templates/validations/_cassandra.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/validations/_cassandra.tpl rename to deployment/charts/kafka/charts/common/templates/validations/_cassandra.tpl diff --git a/deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/validations/_mariadb.tpl b/deployment/charts/kafka/charts/common/templates/validations/_mariadb.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/validations/_mariadb.tpl rename to deployment/charts/kafka/charts/common/templates/validations/_mariadb.tpl diff --git a/deployment/deployment/nginx-ingress-controller/charts/common/templates/validations/_mongodb.tpl b/deployment/charts/kafka/charts/common/templates/validations/_mongodb.tpl similarity index 95% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/validations/_mongodb.tpl rename to deployment/charts/kafka/charts/common/templates/validations/_mongodb.tpl index 1e5bba9..f820ec1 100644 --- a/deployment/deployment/nginx-ingress-controller/charts/common/templates/validations/_mongodb.tpl +++ b/deployment/charts/kafka/charts/common/templates/validations/_mongodb.tpl @@ -22,7 +22,7 @@ Params: {{- $authEnabled := include "common.utils.getValueFromKey" (dict "key" $valueKeyAuthEnabled "context" .context) -}} - {{- if and (not $existingSecret) (eq $enabled "true") (eq $authEnabled "true") -}} + {{- 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" -}} @@ -97,7 +97,7 @@ Auxiliary function to get the right value for architecture Usage: {{ include "common.mongodb.values.architecture" (dict "subchart" "true" "context" $) }} Params: - - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false + - subchart - Boolean - Optional. Whether MongoDB® is used as subchart or not. Default: false */}} {{- define "common.mongodb.values.architecture" -}} {{- if .subchart -}} diff --git a/deployment/charts/kafka/charts/common/templates/validations/_mysql.tpl b/deployment/charts/kafka/charts/common/templates/validations/_mysql.tpl new file mode 100644 index 0000000..74472a0 --- /dev/null +++ b/deployment/charts/kafka/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/deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/validations/_postgresql.tpl b/deployment/charts/kafka/charts/common/templates/validations/_postgresql.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/validations/_postgresql.tpl rename to deployment/charts/kafka/charts/common/templates/validations/_postgresql.tpl diff --git a/deployment/deployment/nginx-ingress-controller/charts/common/templates/validations/_redis.tpl b/deployment/charts/kafka/charts/common/templates/validations/_redis.tpl similarity index 95% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/validations/_redis.tpl rename to deployment/charts/kafka/charts/common/templates/validations/_redis.tpl index 18d9813..dcccfc1 100644 --- a/deployment/deployment/nginx-ingress-controller/charts/common/templates/validations/_redis.tpl +++ b/deployment/charts/kafka/charts/common/templates/validations/_redis.tpl @@ -1,7 +1,7 @@ {{/* vim: set filetype=mustache: */}} {{/* -Validate Redis™ required passwords are not empty. +Validate Redis® required passwords are not empty. Usage: {{ include "common.validations.values.redis.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} @@ -20,7 +20,7 @@ Params: {{- $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 (not $existingSecretValue) (eq $enabled "true") -}} + {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} {{- $requiredPasswords := list -}} {{- $useAuth := include "common.utils.getValueFromKey" (dict "key" $valueKeyRedisUseAuth "context" .context) -}} diff --git a/deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/validations/_validations.tpl b/deployment/charts/kafka/charts/common/templates/validations/_validations.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/redis-cluster/charts/common/templates/validations/_validations.tpl rename to deployment/charts/kafka/charts/common/templates/validations/_validations.tpl diff --git a/deployment/deployment/middleware_deployment/redis-cluster/charts/common/values.yaml b/deployment/charts/kafka/charts/common/values.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/redis-cluster/charts/common/values.yaml rename to deployment/charts/kafka/charts/common/values.yaml diff --git a/deployment/deployment/middleware_deployment/minio/.helmignore b/deployment/charts/kafka/charts/zookeeper/.helmignore similarity index 100% rename from deployment/deployment/middleware_deployment/minio/.helmignore rename to deployment/charts/kafka/charts/zookeeper/.helmignore diff --git a/deployment/charts/kafka/charts/zookeeper/Chart.lock b/deployment/charts/kafka/charts/zookeeper/Chart.lock new file mode 100644 index 0000000..e6b30f2 --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common + repository: https://charts.bitnami.com/bitnami + version: 2.2.1 +digest: sha256:6c67cfa9945bf608209d4e2ca8f17079fca4770907c7902d984187ab5b21811e +generated: "2022-12-09T23:46:15.313038016Z" diff --git a/deployment/charts/kafka/charts/zookeeper/Chart.yaml b/deployment/charts/kafka/charts/zookeeper/Chart.yaml new file mode 100644 index 0000000..26e072a --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/Chart.yaml @@ -0,0 +1,24 @@ +annotations: + category: Infrastructure +apiVersion: v2 +appVersion: 3.8.0 +dependencies: +- name: common + repository: https://charts.bitnami.com/bitnami + tags: + - bitnami-common + version: 2.x.x +description: Apache ZooKeeper provides a reliable, centralized register of configuration + data and services for distributed applications. +home: https://github.com/bitnami/charts/tree/main/bitnami/zookeeper +icon: https://bitnami.com/assets/stacks/zookeeper/img/zookeeper-stack-220x234.png +keywords: +- zookeeper +maintainers: +- name: Bitnami + url: https://github.com/bitnami/charts +name: zookeeper +sources: +- https://github.com/bitnami/containers/tree/main/bitnami/zookeeper +- https://zookeeper.apache.org/ +version: 11.0.2 diff --git a/deployment/charts/kafka/charts/zookeeper/README.md b/deployment/charts/kafka/charts/zookeeper/README.md new file mode 100644 index 0000000..7dfdf54 --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/README.md @@ -0,0 +1,532 @@ + + +# Apache ZooKeeper packaged by Bitnami + +Apache ZooKeeper provides a reliable, centralized register of configuration data and services for distributed applications. + +[Overview of Apache ZooKeeper](https://zookeeper.apache.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 + +```console +$ helm repo add my-repo https://charts.bitnami.com/bitnami +$ helm install my-release my-repo/zookeeper +``` + +## Introduction + +This chart bootstraps a [ZooKeeper](https://github.com/bitnami/containers/tree/main/bitnami/zookeeper) deployment on a [Kubernetes](https://kubernetes.io) cluster using the [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+ +- PV provisioner support in the underlying infrastructure + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```console +$ helm repo add my-repo https://charts.bitnami.com/bitnami +$ helm install my-release my-repo/zookeeper +``` + +These commands deploy ZooKeeper 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: + +```console +$ 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 StorageClass for Persistent Volume(s) | `""` | + + +### Common parameters + +| Name | Description | Value | +| ------------------------ | -------------------------------------------------------------------------------------------- | --------------- | +| `kubeVersion` | Override Kubernetes version | `""` | +| `nameOverride` | String to partially override common.names.fullname template (will maintain the release name) | `""` | +| `fullnameOverride` | String to fully override common.names.fullname template | `""` | +| `clusterDomain` | Kubernetes Cluster Domain | `cluster.local` | +| `extraDeploy` | Extra objects to deploy (evaluated as a template) | `[]` | +| `commonLabels` | Add labels to all the deployed resources | `{}` | +| `commonAnnotations` | Add annotations to all the deployed resources | `{}` | +| `namespaceOverride` | Override namespace for ZooKeeper resources | `""` | +| `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 statefulset | `["sleep"]` | +| `diagnosticMode.args` | Args to override all containers in the statefulset | `["infinity"]` | + + +### ZooKeeper chart parameters + +| Name | Description | Value | +| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ----------------------- | +| `image.registry` | ZooKeeper image registry | `docker.io` | +| `image.repository` | ZooKeeper image repository | `bitnami/zookeeper` | +| `image.tag` | ZooKeeper image tag (immutable tags are recommended) | `3.8.0-debian-11-r65` | +| `image.digest` | ZooKeeper image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | +| `image.pullPolicy` | ZooKeeper image pull policy | `IfNotPresent` | +| `image.pullSecrets` | Specify docker-registry secret names as an array | `[]` | +| `image.debug` | Specify if debug values should be set | `false` | +| `auth.client.enabled` | Enable ZooKeeper client-server authentication. It uses SASL/Digest-MD5 | `false` | +| `auth.client.clientUser` | User that will use ZooKeeper clients to auth | `""` | +| `auth.client.clientPassword` | Password that will use ZooKeeper clients to auth | `""` | +| `auth.client.serverUsers` | Comma, semicolon or whitespace separated list of user to be created | `""` | +| `auth.client.serverPasswords` | Comma, semicolon or whitespace separated list of passwords to assign to users when created | `""` | +| `auth.client.existingSecret` | Use existing secret (ignores previous passwords) | `""` | +| `auth.quorum.enabled` | Enable ZooKeeper server-server authentication. It uses SASL/Digest-MD5 | `false` | +| `auth.quorum.learnerUser` | User that the ZooKeeper quorumLearner will use to authenticate to quorumServers. | `""` | +| `auth.quorum.learnerPassword` | Password that the ZooKeeper quorumLearner will use to authenticate to quorumServers. | `""` | +| `auth.quorum.serverUsers` | Comma, semicolon or whitespace separated list of users for the quorumServers. | `""` | +| `auth.quorum.serverPasswords` | Comma, semicolon or whitespace separated list of passwords to assign to users when created | `""` | +| `auth.quorum.existingSecret` | Use existing secret (ignores previous passwords) | `""` | +| `tickTime` | Basic time unit (in milliseconds) used by ZooKeeper for heartbeats | `2000` | +| `initLimit` | ZooKeeper uses to limit the length of time the ZooKeeper servers in quorum have to connect to a leader | `10` | +| `syncLimit` | How far out of date a server can be from a leader | `5` | +| `preAllocSize` | Block size for transaction log file | `65536` | +| `snapCount` | The number of transactions recorded in the transaction log before a snapshot can be taken (and the transaction log rolled) | `100000` | +| `maxClientCnxns` | Limits the number of concurrent connections that a single client may make to a single member of the ZooKeeper ensemble | `60` | +| `maxSessionTimeout` | Maximum session timeout (in milliseconds) that the server will allow the client to negotiate | `40000` | +| `heapSize` | Size (in MB) for the Java Heap options (Xmx and Xms) | `1024` | +| `fourlwCommandsWhitelist` | A list of comma separated Four Letter Words commands that can be executed | `srvr, mntr, ruok` | +| `minServerId` | Minimal SERVER_ID value, nodes increment their IDs respectively | `1` | +| `listenOnAllIPs` | Allow ZooKeeper to listen for connections from its peers on all available IP addresses | `false` | +| `autopurge.snapRetainCount` | The most recent snapshots amount (and corresponding transaction logs) to retain | `3` | +| `autopurge.purgeInterval` | The time interval (in hours) for which the purge task has to be triggered | `0` | +| `logLevel` | Log level for the ZooKeeper server. ERROR by default | `ERROR` | +| `jvmFlags` | Default JVM flags for the ZooKeeper process | `""` | +| `dataLogDir` | Dedicated data log directory | `""` | +| `configuration` | Configure ZooKeeper with a custom zoo.cfg file | `""` | +| `existingConfigmap` | The name of an existing ConfigMap with your custom configuration for ZooKeeper | `""` | +| `extraEnvVars` | Array with extra environment variables to add to ZooKeeper nodes | `[]` | +| `extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for ZooKeeper nodes | `""` | +| `extraEnvVarsSecret` | Name of existing Secret containing extra env vars for ZooKeeper nodes | `""` | +| `command` | Override default container command (useful when using custom images) | `["/scripts/setup.sh"]` | +| `args` | Override default container args (useful when using custom images) | `[]` | + + +### Statefulset parameters + +| Name | Description | Value | +| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | +| `replicaCount` | Number of ZooKeeper nodes | `1` | +| `containerPorts.client` | ZooKeeper client container port | `2181` | +| `containerPorts.tls` | ZooKeeper TLS container port | `3181` | +| `containerPorts.follower` | ZooKeeper follower container port | `2888` | +| `containerPorts.election` | ZooKeeper election container port | `3888` | +| `livenessProbe.enabled` | Enable livenessProbe on ZooKeeper containers | `true` | +| `livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `30` | +| `livenessProbe.periodSeconds` | Period seconds for livenessProbe | `10` | +| `livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `5` | +| `livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `6` | +| `livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | +| `livenessProbe.probeCommandTimeout` | Probe command timeout for livenessProbe | `2` | +| `readinessProbe.enabled` | Enable readinessProbe on ZooKeeper containers | `true` | +| `readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `5` | +| `readinessProbe.periodSeconds` | Period seconds for readinessProbe | `10` | +| `readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `5` | +| `readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `6` | +| `readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | +| `readinessProbe.probeCommandTimeout` | Probe command timeout for readinessProbe | `2` | +| `startupProbe.enabled` | Enable startupProbe on ZooKeeper containers | `false` | +| `startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `30` | +| `startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | +| `startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `1` | +| `startupProbe.failureThreshold` | Failure threshold for startupProbe | `15` | +| `startupProbe.successThreshold` | Success threshold for startupProbe | `1` | +| `customLivenessProbe` | Custom livenessProbe that overrides the default one | `{}` | +| `customReadinessProbe` | Custom readinessProbe that overrides the default one | `{}` | +| `customStartupProbe` | Custom startupProbe that overrides the default one | `{}` | +| `lifecycleHooks` | for the ZooKeeper container(s) to automate configuration before or after startup | `{}` | +| `resources.limits` | The resources limits for the ZooKeeper containers | `{}` | +| `resources.requests.memory` | The requested memory for the ZooKeeper containers | `256Mi` | +| `resources.requests.cpu` | The requested cpu for the ZooKeeper containers | `250m` | +| `podSecurityContext.enabled` | Enabled ZooKeeper pods' Security Context | `true` | +| `podSecurityContext.fsGroup` | Set ZooKeeper pod's Security Context fsGroup | `1001` | +| `containerSecurityContext.enabled` | Enabled ZooKeeper containers' Security Context | `true` | +| `containerSecurityContext.runAsUser` | Set ZooKeeper containers' Security Context runAsUser | `1001` | +| `containerSecurityContext.runAsNonRoot` | Set ZooKeeper containers' Security Context runAsNonRoot | `true` | +| `containerSecurityContext.allowPrivilegeEscalation` | Force the child process to be run as nonprivilege | `false` | +| `hostAliases` | ZooKeeper pods host aliases | `[]` | +| `podLabels` | Extra labels for ZooKeeper pods | `{}` | +| `podAnnotations` | Annotations for ZooKeeper pods | `{}` | +| `podAffinityPreset` | Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `podAntiAffinityPreset` | Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `nodeAffinityPreset.type` | Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `nodeAffinityPreset.key` | Node label key to match Ignored if `affinity` is set. | `""` | +| `nodeAffinityPreset.values` | Node label values to match. Ignored if `affinity` is set. | `[]` | +| `affinity` | Affinity for pod assignment | `{}` | +| `nodeSelector` | Node labels for pod assignment | `{}` | +| `tolerations` | Tolerations for pod assignment | `[]` | +| `topologySpreadConstraints` | Topology Spread Constraints for pod assignment spread across your cluster among failure-domains. Evaluated as a template | `[]` | +| `podManagementPolicy` | StatefulSet controller supports relax its ordering guarantees while preserving its uniqueness and identity guarantees. There are two valid pod management policies: `OrderedReady` and `Parallel` | `Parallel` | +| `priorityClassName` | Name of the existing priority class to be used by ZooKeeper pods, priority class needs to be created beforehand | `""` | +| `schedulerName` | Kubernetes pod scheduler registry | `""` | +| `updateStrategy.type` | ZooKeeper statefulset strategy type | `RollingUpdate` | +| `updateStrategy.rollingUpdate` | ZooKeeper statefulset rolling update configuration parameters | `{}` | +| `extraVolumes` | Optionally specify extra list of additional volumes for the ZooKeeper pod(s) | `[]` | +| `extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the ZooKeeper container(s) | `[]` | +| `sidecars` | Add additional sidecar containers to the ZooKeeper pod(s) | `[]` | +| `initContainers` | Add additional init containers to the ZooKeeper pod(s) | `[]` | +| `pdb.create` | Deploy a pdb object for the ZooKeeper pod | `false` | +| `pdb.minAvailable` | Minimum available ZooKeeper replicas | `""` | +| `pdb.maxUnavailable` | Maximum unavailable ZooKeeper replicas | `1` | + + +### Traffic Exposure parameters + +| Name | Description | Value | +| ------------------------------------------- | --------------------------------------------------------------------------------------- | ----------- | +| `service.type` | Kubernetes Service type | `ClusterIP` | +| `service.ports.client` | ZooKeeper client service port | `2181` | +| `service.ports.tls` | ZooKeeper TLS service port | `3181` | +| `service.ports.follower` | ZooKeeper follower service port | `2888` | +| `service.ports.election` | ZooKeeper election service port | `3888` | +| `service.nodePorts.client` | Node port for clients | `""` | +| `service.nodePorts.tls` | Node port for TLS | `""` | +| `service.disableBaseClientPort` | Remove client port from service definitions. | `false` | +| `service.sessionAffinity` | Control where client requests go, to the same pod or round-robin | `None` | +| `service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | +| `service.clusterIP` | ZooKeeper service Cluster IP | `""` | +| `service.loadBalancerIP` | ZooKeeper service Load Balancer IP | `""` | +| `service.loadBalancerSourceRanges` | ZooKeeper service Load Balancer sources | `[]` | +| `service.externalTrafficPolicy` | ZooKeeper service external traffic policy | `Cluster` | +| `service.annotations` | Additional custom annotations for ZooKeeper service | `{}` | +| `service.extraPorts` | Extra ports to expose in the ZooKeeper service (normally used with the `sidecar` value) | `[]` | +| `service.headless.annotations` | Annotations for the Headless Service | `{}` | +| `service.headless.publishNotReadyAddresses` | If the ZooKeeper headless service should publish DNS records for not ready pods | `true` | +| `networkPolicy.enabled` | Specifies whether a NetworkPolicy should be created | `false` | +| `networkPolicy.allowExternal` | Don't require client label for connections | `true` | + + +### Other Parameters + +| Name | Description | Value | +| --------------------------------------------- | ---------------------------------------------------------------------- | ------- | +| `serviceAccount.create` | Enable creation of ServiceAccount for ZooKeeper pod | `false` | +| `serviceAccount.name` | The name of the ServiceAccount to use. | `""` | +| `serviceAccount.automountServiceAccountToken` | Allows auto mount of ServiceAccountToken on the serviceAccount created | `true` | +| `serviceAccount.annotations` | Additional custom annotations for the ServiceAccount | `{}` | + + +### Persistence parameters + +| Name | Description | Value | +| -------------------------------------- | ------------------------------------------------------------------------------ | ------------------- | +| `persistence.enabled` | Enable ZooKeeper data persistence using PVC. If false, use emptyDir | `true` | +| `persistence.existingClaim` | Name of an existing PVC to use (only when deploying a single replica) | `""` | +| `persistence.storageClass` | PVC Storage Class for ZooKeeper data volume | `""` | +| `persistence.accessModes` | PVC Access modes | `["ReadWriteOnce"]` | +| `persistence.size` | PVC Storage Request for ZooKeeper data volume | `8Gi` | +| `persistence.annotations` | Annotations for the PVC | `{}` | +| `persistence.labels` | Labels for the PVC | `{}` | +| `persistence.selector` | Selector to match an existing Persistent Volume for ZooKeeper's data PVC | `{}` | +| `persistence.dataLogDir.size` | PVC Storage Request for ZooKeeper's dedicated data log directory | `8Gi` | +| `persistence.dataLogDir.existingClaim` | Provide an existing `PersistentVolumeClaim` for ZooKeeper's data log directory | `""` | +| `persistence.dataLogDir.selector` | Selector to match an existing Persistent Volume for ZooKeeper's data log PVC | `{}` | + + +### Volume Permissions parameters + +| Name | Description | Value | +| ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | +| `volumePermissions.enabled` | Enable init container that changes the owner and group of the persistent volume | `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-r60` | +| `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` | Init container volume-permissions image pull secrets | `[]` | +| `volumePermissions.resources.limits` | Init container volume-permissions resource limits | `{}` | +| `volumePermissions.resources.requests` | Init container volume-permissions resource requests | `{}` | +| `volumePermissions.containerSecurityContext.enabled` | Enabled init container Security Context | `true` | +| `volumePermissions.containerSecurityContext.runAsUser` | User ID for the init container | `0` | + + +### Metrics parameters + +| Name | Description | Value | +| ------------------------------------------ | ------------------------------------------------------------------------------------- | ----------- | +| `metrics.enabled` | Enable Prometheus to access ZooKeeper metrics endpoint | `false` | +| `metrics.containerPort` | ZooKeeper Prometheus Exporter container port | `9141` | +| `metrics.service.type` | ZooKeeper Prometheus Exporter service type | `ClusterIP` | +| `metrics.service.port` | ZooKeeper Prometheus Exporter service port | `9141` | +| `metrics.service.annotations` | Annotations for Prometheus to auto-discover the metrics endpoint | `{}` | +| `metrics.serviceMonitor.enabled` | Create ServiceMonitor Resource for scraping metrics using Prometheus Operator | `false` | +| `metrics.serviceMonitor.namespace` | Namespace for the ServiceMonitor Resource (defaults to the Release Namespace) | `""` | +| `metrics.serviceMonitor.interval` | Interval at which metrics should be scraped. | `""` | +| `metrics.serviceMonitor.scrapeTimeout` | Timeout after which the scrape is ended | `""` | +| `metrics.serviceMonitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | `{}` | +| `metrics.serviceMonitor.selector` | Prometheus instance selector labels | `{}` | +| `metrics.serviceMonitor.relabelings` | RelabelConfigs to apply to samples before scraping | `[]` | +| `metrics.serviceMonitor.metricRelabelings` | MetricRelabelConfigs to apply to samples before ingestion | `[]` | +| `metrics.serviceMonitor.honorLabels` | Specify honorLabels parameter to add the scrape endpoint | `false` | +| `metrics.serviceMonitor.jobLabel` | The name of the label on the target service to use as the job name in prometheus. | `""` | +| `metrics.prometheusRule.enabled` | Create a PrometheusRule for Prometheus Operator | `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` | PrometheusRule definitions | `[]` | + + +### TLS/SSL parameters + +| Name | Description | Value | +| ----------------------------------------- | -------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | +| `tls.client.enabled` | Enable TLS for client connections | `false` | +| `tls.client.auth` | SSL Client auth. Can be "none", "want" or "need". | `none` | +| `tls.client.autoGenerated` | Generate automatically self-signed TLS certificates for ZooKeeper client communications | `false` | +| `tls.client.existingSecret` | Name of the existing secret containing the TLS certificates for ZooKeeper client communications | `""` | +| `tls.client.existingSecretKeystoreKey` | The secret key from the tls.client.existingSecret containing the Keystore. | `""` | +| `tls.client.existingSecretTruststoreKey` | The secret key from the tls.client.existingSecret containing the Truststore. | `""` | +| `tls.client.keystorePath` | Location of the KeyStore file used for Client connections | `/opt/bitnami/zookeeper/config/certs/client/zookeeper.keystore.jks` | +| `tls.client.truststorePath` | Location of the TrustStore file used for Client connections | `/opt/bitnami/zookeeper/config/certs/client/zookeeper.truststore.jks` | +| `tls.client.passwordsSecretName` | Existing secret containing Keystore and truststore passwords | `""` | +| `tls.client.passwordsSecretKeystoreKey` | The secret key from the tls.client.passwordsSecretName containing the password for the Keystore. | `""` | +| `tls.client.passwordsSecretTruststoreKey` | The secret key from the tls.client.passwordsSecretName containing the password for the Truststore. | `""` | +| `tls.client.keystorePassword` | Password to access KeyStore if needed | `""` | +| `tls.client.truststorePassword` | Password to access TrustStore if needed | `""` | +| `tls.quorum.enabled` | Enable TLS for quorum protocol | `false` | +| `tls.quorum.auth` | SSL Quorum Client auth. Can be "none", "want" or "need". | `none` | +| `tls.quorum.autoGenerated` | Create self-signed TLS certificates. Currently only supports PEM certificates. | `false` | +| `tls.quorum.existingSecret` | Name of the existing secret containing the TLS certificates for ZooKeeper quorum protocol | `""` | +| `tls.quorum.existingSecretKeystoreKey` | The secret key from the tls.quorum.existingSecret containing the Keystore. | `""` | +| `tls.quorum.existingSecretTruststoreKey` | The secret key from the tls.quorum.existingSecret containing the Truststore. | `""` | +| `tls.quorum.keystorePath` | Location of the KeyStore file used for Quorum protocol | `/opt/bitnami/zookeeper/config/certs/quorum/zookeeper.keystore.jks` | +| `tls.quorum.truststorePath` | Location of the TrustStore file used for Quorum protocol | `/opt/bitnami/zookeeper/config/certs/quorum/zookeeper.truststore.jks` | +| `tls.quorum.passwordsSecretName` | Existing secret containing Keystore and truststore passwords | `""` | +| `tls.quorum.passwordsSecretKeystoreKey` | The secret key from the tls.quorum.passwordsSecretName containing the password for the Keystore. | `""` | +| `tls.quorum.passwordsSecretTruststoreKey` | The secret key from the tls.quorum.passwordsSecretName containing the password for the Truststore. | `""` | +| `tls.quorum.keystorePassword` | Password to access KeyStore if needed | `""` | +| `tls.quorum.truststorePassword` | Password to access TrustStore if needed | `""` | +| `tls.resources.limits` | The resources limits for the TLS init container | `{}` | +| `tls.resources.requests` | The requested resources for the TLS init container | `{}` | + + +Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +$ helm install my-release \ + --set auth.clientUser=newUser \ + my-repo/zookeeper +``` + +The above command sets the ZooKeeper user to `newUser`. + +> 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, + +```console +$ helm install my-release -f values.yaml my-repo/zookeeper +``` + +> **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. + +### Configure log level + +You can configure the ZooKeeper log level using the `ZOO_LOG_LEVEL` environment variable or the parameter `logLevel`. By default, it is set to `ERROR` because each use of the liveness probe and the readiness probe produces an `INFO` message on connection and a `WARN` message on disconnection, generating a high volume of noise in your logs. + +In order to remove that log noise so levels can be set to 'INFO', two changes must be made. + +First, ensure that you are not getting metrics via the deprecated pattern of polling 'mntr' on the ZooKeeper client port. The preferred method of polling for Apache ZooKeeper metrics is the ZooKeeper metrics server. This is supported in this chart when setting `metrics.enabled` to `true`. + +Second, to avoid the connection/disconnection messages from the probes, you can set custom values for these checks which direct them to the ZooKeeper Admin Server instead of the client port. By default, an Admin Server will be started that listens on `localhost` at port `8080`. The following is an example of this use of the Admin Server for probes: + +``` +livenessProbe: + enabled: false +readinessProbe: + enabled: false +customLivenessProbe: + exec: + command: ['/bin/bash', '-c', 'curl -s -m 2 http://localhost:8080/commands/ruok | grep ruok'] + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 6 +customReadinessProbe: + exec: + command: ['/bin/bash', '-c', 'curl -s -m 2 http://localhost:8080/commands/ruok | grep error | grep null'] + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 6 +``` + +You can also set the log4j logging level and what log appenders are turned on, by using `ZOO_LOG4J_PROP` set inside of conf/log4j.properties as zookeeper.root.logger by default to + +```console +zookeeper.root.logger=INFO, CONSOLE +``` +the available appender is + +- CONSOLE +- ROLLINGFILE +- RFAAUDIT +- TRACEFILE + +## Persistence + +The [Bitnami ZooKeeper](https://github.com/bitnami/containers/tree/main/bitnami/zookeeper) image stores the ZooKeeper data and configurations at the `/bitnami/zookeeper` path of the container. + +Persistent Volume Claims are used to keep the data across deployments. This is known to work in GCE, AWS, and minikube. See the [Parameters](#parameters) section to configure the PVC or to disable persistence. + +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`. + +### Configure the data log directory + +You can use a dedicated device for logs (instead of using the data directory) to help avoiding competition between logging and snaphots. To do so, set the `dataLogDir` parameter with the path to be used for writing transaction logs. Alternatively, set this parameter with an empty string and it will result in the log being written to the data directory (Zookeeper's default behavior). + +When using a dedicated device for logs, you can use a PVC to persist the logs. To do so, set `persistence.enabled` to `true`. See the [Persistence Parameters](#persistence-parameters) section for more information. + +### Set pod affinity + +This chart allows you to set custom pod affinity using the `affinity` parameter. Find more information about pod affinity in the [Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity). + +As an alternative, you can use any of the preset configurations for pod affinity, pod anti-affinity, and node affinity available at the [bitnami/common](https://github.com/bitnami/charts/tree/main/bitnami/common#affinities) chart. To do so, set the `podAffinityPreset`, `podAntiAffinityPreset`, or `nodeAffinityPreset` parameters. + +## 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 + +### To 11.0.0 + +This major version removes `commonAnnotations` and `commonLabels` from `volumeClaimTemplates`. Now annotations and labels can be set in volume claims using `persistence.annotations` and `persistence.labels` values. If the previous deployment has already set `commonAnnotations` and/or `commonLabels` values, to ensure a clean upgrade from previous version without loosing data, please set `persistence.annotations` and/or `persistence.labels` values with the same content as the common values. + +### To 10.0.0 + +This new version of the chart adds support for server-server authentication. +The chart previously supported client-server authentication, to avoid confusion, the previous parameters have been renamed from `auth.*` to `auth.client.*`. + +### To 9.0.0 + +This new version of the chart includes the new ZooKeeper major version 3.8.0. Upgrade compatibility is not guaranteed. + +### To 8.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: + +- `allowAnonymousLogin` is deprecated. +- `containerPort`, `tlsContainerPort`, `followerContainerPort` and `electionContainerPort` have been regrouped under the `containerPorts` map. +- `service.port`, `service.tlsClientPort`, `service.followerPort`, and `service.electionPort` have been regrouped under the `service.ports` map. +- `updateStrategy` (string) and `rollingUpdatePartition` are regrouped under the `updateStrategy` map. +- `podDisruptionBudget.*` parameters are renamed to `pdb.*`. + +### To 7.0.0 + +This new version renames the parameters used to configure TLS for both client and quorum. + +- `service.tls.disable_base_client_port` is renamed to `service.disableBaseClientPort` +- `service.tls.client_port` is renamed to `service.tlsClientPort` +- `service.tls.client_enable` is renamed to `tls.client.enabled` +- `service.tls.client_keystore_path` is renamed to `tls.client.keystorePath` +- `service.tls.client_truststore_path` is renamed to `tls.client.truststorePath` +- `service.tls.client_keystore_password` is renamed to `tls.client.keystorePassword` +- `service.tls.client_truststore_password` is renamed to `tls.client.truststorePassword` +- `service.tls.quorum_enable` is renamed to `tls.quorum.enabled` +- `service.tls.quorum_keystore_path` is renamed to `tls.quorum.keystorePath` +- `service.tls.quorum_truststore_path` is renamed to `tls.quorum.truststorePath` +- `service.tls.quorum_keystore_password` is renamed to `tls.quorum.keystorePassword` +- `service.tls.quorum_truststore_password` is renamed to `tls.quorum.truststorePassword` + +### To 6.1.0 + +This version 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. + +### To 6.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/zookeeper/administration/upgrade-helm3/). + +### To 5.21.0 + +A couple of parameters related to Zookeeper metrics were renamed or disappeared in favor of new ones: + +- `metrics.port` is renamed to `metrics.containerPort`. +- `metrics.annotations` is deprecated in favor of `metrics.service.annotations`. + +### To 3.0.0 + +This new version of the chart includes the new ZooKeeper major version 3.5.5. Note that to perform an automatic upgrade +of the application, each node will need to have at least one snapshot file created in the data directory. If not, the +new version of the application won't be able to start the service. Please refer to [ZOOKEEPER-3056](https://issues.apache.org/jira/browse/ZOOKEEPER-3056) +in order to find ways to workaround this issue in case you are facing it. + +### To 2.0.0 + +Backwards compatibility is not guaranteed unless you modify the labels used on the chart's statefulsets. +Use the workaround below to upgrade from versions previous to 2.0.0. The following example assumes that the release name is `zookeeper`: + +```console +$ kubectl delete statefulset zookeeper-zookeeper --cascade=false +``` + +### To 1.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 1.0.0. The following example assumes that the release name is zookeeper: + +```console +$ kubectl delete statefulset zookeeper-zookeeper --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/deployment/deployment/middleware_deployment/redis-cluster/charts/common/.helmignore b/deployment/charts/kafka/charts/zookeeper/charts/common/.helmignore similarity index 100% rename from deployment/deployment/middleware_deployment/redis-cluster/charts/common/.helmignore rename to deployment/charts/kafka/charts/zookeeper/charts/common/.helmignore diff --git a/deployment/charts/kafka/charts/zookeeper/charts/common/Chart.yaml b/deployment/charts/kafka/charts/zookeeper/charts/common/Chart.yaml new file mode 100644 index 0000000..653c063 --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/charts/common/Chart.yaml @@ -0,0 +1,23 @@ +annotations: + category: Infrastructure +apiVersion: v2 +appVersion: 2.2.1 +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.1 diff --git a/deployment/charts/kafka/charts/zookeeper/charts/common/README.md b/deployment/charts/kafka/charts/zookeeper/charts/common/README.md new file mode 100644 index 0000000..ec43a5f --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/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/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_affinities.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_affinities.tpl new file mode 100644 index 0000000..81902a6 --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/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/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_capabilities.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_capabilities.tpl new file mode 100644 index 0000000..9d9b760 --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/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/deployment/deployment/nginx-ingress-controller/charts/common/templates/_errors.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_errors.tpl similarity index 100% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/_errors.tpl rename to deployment/charts/kafka/charts/zookeeper/charts/common/templates/_errors.tpl diff --git a/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_images.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_images.tpl new file mode 100644 index 0000000..46c659e --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/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/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_ingress.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_ingress.tpl new file mode 100644 index 0000000..831da9c --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/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/deployment/deployment/nginx-ingress-controller/charts/common/templates/_labels.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_labels.tpl similarity index 100% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/_labels.tpl rename to deployment/charts/kafka/charts/zookeeper/charts/common/templates/_labels.tpl diff --git a/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_names.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_names.tpl new file mode 100644 index 0000000..1bdac8b --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_names.tpl @@ -0,0 +1,70 @@ +{{/* 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" -}} +{{- if .Values.namespaceOverride -}} +{{- .Values.namespaceOverride -}} +{{- else -}} +{{- .Release.Namespace -}} +{{- end -}} +{{- 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/deployment/deployment/nginx-ingress-controller/charts/common/templates/_secrets.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_secrets.tpl similarity index 67% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/_secrets.tpl rename to deployment/charts/kafka/charts/zookeeper/charts/common/templates/_secrets.tpl index 60b84a7..4267d42 100644 --- a/deployment/deployment/nginx-ingress-controller/charts/common/templates/_secrets.tpl +++ b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_secrets.tpl @@ -8,7 +8,7 @@ Usage: 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/master/bitnami/common#existingsecret + +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. */}} @@ -41,7 +41,7 @@ Usage: 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/master/bitnami/common#existingsecret + +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" -}} @@ -72,6 +72,15 @@ Params: - 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" -}} @@ -81,10 +90,12 @@ Params: {{- $passwordLength := default 10 .length }} {{- $providedPasswordKey := include "common.utils.getKeyFromList" (dict "keys" .providedValues "context" $.context) }} {{- $providedPasswordValue := include "common.utils.getValueFromKey" (dict "key" $providedPasswordKey "context" $.context) }} -{{- $secret := (lookup "v1" "Secret" $.context.Release.Namespace .secret) }} -{{- if $secret }} - {{- if index $secret.data .key }} - {{- $password = index $secret.data .key }} +{{- $secretData := (lookup "v1" "Secret" $.context.Release.Namespace .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 }} @@ -98,7 +109,7 @@ Params: {{- $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 }} @@ -111,6 +122,31 @@ Params: {{- 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" $.context.Release.Namespace .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 diff --git a/deployment/deployment/nginx-ingress-controller/charts/common/templates/_storage.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_storage.tpl similarity index 100% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/_storage.tpl rename to deployment/charts/kafka/charts/zookeeper/charts/common/templates/_storage.tpl diff --git a/deployment/deployment/nginx-ingress-controller/charts/common/templates/_tplvalues.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_tplvalues.tpl similarity index 100% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/_tplvalues.tpl rename to deployment/charts/kafka/charts/zookeeper/charts/common/templates/_tplvalues.tpl diff --git a/deployment/deployment/nginx-ingress-controller/charts/common/templates/_utils.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_utils.tpl similarity index 98% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/_utils.tpl rename to deployment/charts/kafka/charts/zookeeper/charts/common/templates/_utils.tpl index ea083a2..8c22b2a 100644 --- a/deployment/deployment/nginx-ingress-controller/charts/common/templates/_utils.tpl +++ b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_utils.tpl @@ -6,7 +6,7 @@ Usage: */}} {{- define "common.utils.secret.getvalue" -}} {{- $varname := include "common.utils.fieldToEnvVar" . -}} -export {{ $varname }}=$(kubectl get secret --namespace {{ .context.Release.Namespace | quote }} {{ .secret }} -o jsonpath="{.data.{{ .field }}}" | base64 --decode) +export {{ $varname }}=$(kubectl get secret --namespace {{ .context.Release.Namespace | quote }} {{ .secret }} -o jsonpath="{.data.{{ .field }}}" | base64 -d) {{- end -}} {{/* diff --git a/deployment/deployment/nginx-ingress-controller/charts/common/templates/_warnings.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/_warnings.tpl similarity index 100% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/_warnings.tpl rename to deployment/charts/kafka/charts/zookeeper/charts/common/templates/_warnings.tpl diff --git a/deployment/deployment/nginx-ingress-controller/charts/common/templates/validations/_cassandra.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_cassandra.tpl similarity index 96% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/validations/_cassandra.tpl rename to deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_cassandra.tpl index 8679ddf..ded1ae3 100644 --- a/deployment/deployment/nginx-ingress-controller/charts/common/templates/validations/_cassandra.tpl +++ b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_cassandra.tpl @@ -14,7 +14,7 @@ Params: {{- $dbUserPrefix := include "common.cassandra.values.key.dbUser" . -}} {{- $valueKeyPassword := printf "%s.password" $dbUserPrefix -}} - {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} {{- $requiredPasswords := list -}} {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "cassandra-password" -}} diff --git a/deployment/deployment/nginx-ingress-controller/charts/common/templates/validations/_mariadb.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_mariadb.tpl similarity index 97% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/validations/_mariadb.tpl rename to deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_mariadb.tpl index bb5ed72..b6906ff 100644 --- a/deployment/deployment/nginx-ingress-controller/charts/common/templates/validations/_mariadb.tpl +++ b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_mariadb.tpl @@ -18,7 +18,7 @@ Params: {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} {{- $valueKeyReplicationPassword := printf "%s.replicationPassword" $authPrefix -}} - {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} {{- $requiredPasswords := list -}} {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mariadb-root-password" -}} diff --git a/deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_mongodb.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_mongodb.tpl new file mode 100644 index 0000000..f820ec1 --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/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/deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_mysql.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_mysql.tpl new file mode 100644 index 0000000..74472a0 --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/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/deployment/deployment/nginx-ingress-controller/charts/common/templates/validations/_postgresql.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_postgresql.tpl similarity index 98% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/validations/_postgresql.tpl rename to deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_postgresql.tpl index 992bcd3..164ec0d 100644 --- a/deployment/deployment/nginx-ingress-controller/charts/common/templates/validations/_postgresql.tpl +++ b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_postgresql.tpl @@ -13,10 +13,8 @@ Params: {{- $enabled := include "common.postgresql.values.enabled" . -}} {{- $valueKeyPostgresqlPassword := include "common.postgresql.values.key.postgressPassword" . -}} {{- $valueKeyPostgresqlReplicationEnabled := include "common.postgresql.values.key.replicationPassword" . -}} - - {{- if and (not $existingSecret) (eq $enabled "true") -}} + {{- 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 -}} diff --git a/deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_redis.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_redis.tpl new file mode 100644 index 0000000..dcccfc1 --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/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/deployment/deployment/nginx-ingress-controller/charts/common/templates/validations/_validations.tpl b/deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_validations.tpl similarity index 100% rename from deployment/deployment/nginx-ingress-controller/charts/common/templates/validations/_validations.tpl rename to deployment/charts/kafka/charts/zookeeper/charts/common/templates/validations/_validations.tpl diff --git a/deployment/deployment/nginx-ingress-controller/charts/common/values.yaml b/deployment/charts/kafka/charts/zookeeper/charts/common/values.yaml similarity index 100% rename from deployment/deployment/nginx-ingress-controller/charts/common/values.yaml rename to deployment/charts/kafka/charts/zookeeper/charts/common/values.yaml diff --git a/deployment/charts/kafka/charts/zookeeper/templates/NOTES.txt b/deployment/charts/kafka/charts/zookeeper/templates/NOTES.txt new file mode 100644 index 0000000..c287e1e --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/templates/NOTES.txt @@ -0,0 +1,76 @@ +CHART NAME: {{ .Chart.Name }} +CHART VERSION: {{ .Chart.Version }} +APP VERSION: {{ .Chart.AppVersion }} + +{{- if and (not .Values.auth.client.enabled) (eq .Values.service.type "LoadBalancer") }} +------------------------------------------------------------------------------- + WARNING + + By specifying "serviceType=LoadBalancer" and not specifying "auth.enabled=true" + you have most likely exposed the ZooKeeper service externally without any + authentication mechanism. + + For security reasons, we strongly suggest that you switch to "ClusterIP" or + "NodePort". As alternative, you can also specify a valid password on the + "auth.clientPassword" parameter. + +------------------------------------------------------------------------------- +{{- end }} + +** 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/zookeeper/entrypoint.sh /opt/bitnami/scripts/zookeeper/run.sh + +{{- else }} + +ZooKeeper can be accessed via port {{ .Values.service.ports.client }} on the following DNS name from within your cluster: + + {{ template "common.names.fullname" . }}.{{ template "zookeeper.namespace" . }}.svc.{{ .Values.clusterDomain }} + +To connect to your ZooKeeper server run the following commands: + + export POD_NAME=$(kubectl get pods --namespace {{ template "zookeeper.namespace" . }} -l "app.kubernetes.io/name={{ template "common.names.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=zookeeper" -o jsonpath="{.items[0].metadata.name}") + kubectl exec -it $POD_NAME -- zkCli.sh + +To connect to your ZooKeeper server from outside the cluster execute the following commands: + +{{- if eq .Values.service.type "NodePort" }} + + export NODE_IP=$(kubectl get nodes --namespace {{ template "zookeeper.namespace" . }} -o jsonpath="{.items[0].status.addresses[0].address}") + export NODE_PORT=$(kubectl get --namespace {{ template "zookeeper.namespace" . }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "common.names.fullname" . }}) + zkCli.sh $NODE_IP:$NODE_PORT + +{{- else if eq .Values.service.type "LoadBalancer" }} + + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + Watch the status with: 'kubectl get svc --namespace {{ template "zookeeper.namespace" . }} -w {{ template "common.names.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ template "zookeeper.namespace" . }} {{ template "common.names.fullname" . }} --template "{{ "{{ range (index .status.loadBalancer.ingress 0) }}{{ . }}{{ end }}" }}") + zkCli.sh $SERVICE_IP:{{ .Values.service.ports.client }} + +{{- else if eq .Values.service.type "ClusterIP" }} + + kubectl port-forward --namespace {{ template "zookeeper.namespace" . }} svc/{{ template "common.names.fullname" . }} {{ .Values.service.ports.client }}:{{ .Values.containerPorts.client }} & + zkCli.sh 127.0.0.1:{{ .Values.service.ports.client }} + +{{- end }} +{{- end }} + +{{- include "zookeeper.validateValues" . }} +{{- include "zookeeper.checkRollingTags" . }} diff --git a/deployment/charts/kafka/charts/zookeeper/templates/_helpers.tpl b/deployment/charts/kafka/charts/zookeeper/templates/_helpers.tpl new file mode 100644 index 0000000..d855bad --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/templates/_helpers.tpl @@ -0,0 +1,361 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Return the proper ZooKeeper image name +*/}} +{{- define "zookeeper.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper image name (for the init container volume-permissions image) +*/}} +{{- define "zookeeper.volumePermissions.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.volumePermissions.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names +*/}} +{{- define "zookeeper.imagePullSecrets" -}} +{{- include "common.images.pullSecrets" (dict "images" (list .Values.image .Values.volumePermissions.image) "global" .Values.global) -}} +{{- end -}} + +{{/* +Check if there are rolling tags in the images +*/}} +{{- define "zookeeper.checkRollingTags" -}} +{{- include "common.warnings.rollingTag" .Values.image }} +{{- include "common.warnings.rollingTag" .Values.volumePermissions.image }} +{{- end -}} + +{{/* +Return ZooKeeper Namespace to use +*/}} +{{- define "zookeeper.namespace" -}} +{{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} +{{- else -}} + {{- .Release.Namespace -}} +{{- end -}} +{{- end -}} + +{{/* + Create the name of the service account to use + */}} +{{- define "zookeeper.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "common.names.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Return the ZooKeeper client-server authentication credentials secret +*/}} +{{- define "zookeeper.client.secretName" -}} +{{- if .Values.auth.client.existingSecret -}} + {{- printf "%s" (tpl .Values.auth.client.existingSecret $) -}} +{{- else -}} + {{- printf "%s-client-auth" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return the ZooKeeper server-server authentication credentials secret +*/}} +{{- define "zookeeper.quorum.secretName" -}} +{{- if .Values.auth.quorum.existingSecret -}} + {{- printf "%s" (tpl .Values.auth.quorum.existingSecret $) -}} +{{- else -}} + {{- printf "%s-quorum-auth" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a ZooKeeper client-server authentication credentials secret object should be created +*/}} +{{- define "zookeeper.client.createSecret" -}} +{{- if and .Values.auth.client.enabled (empty .Values.auth.client.existingSecret) -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a ZooKeeper server-server authentication credentials secret object should be created +*/}} +{{- define "zookeeper.quorum.createSecret" -}} +{{- if and .Values.auth.quorum.enabled (empty .Values.auth.quorum.existingSecret) -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Returns the available value for certain key in an existing secret (if it exists), +otherwise it generates a random value. +*/}} +{{- define "getValueFromSecret" }} + {{- $len := (default 16 .Length) | int -}} + {{- $obj := (lookup "v1" "Secret" .Namespace .Name).data -}} + {{- if $obj }} + {{- index $obj .Key | b64dec -}} + {{- else -}} + {{- randAlphaNum $len -}} + {{- end -}} +{{- end }} + +{{/* +Return the ZooKeeper configuration ConfigMap name +*/}} +{{- define "zookeeper.configmapName" -}} +{{- if .Values.existingConfigmap -}} + {{- printf "%s" (tpl .Values.existingConfigmap $) -}} +{{- else -}} + {{- printf "%s" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a ConfigMap object should be created for ZooKeeper configuration +*/}} +{{- define "zookeeper.createConfigmap" -}} +{{- if and .Values.configuration (not .Values.existingConfigmap) }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a TLS secret should be created for ZooKeeper quorum +*/}} +{{- define "zookeeper.quorum.createTlsSecret" -}} +{{- if and .Values.tls.quorum.enabled .Values.tls.quorum.autoGenerated (not .Values.tls.quorum.existingSecret) }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return the secret containing ZooKeeper quorum TLS certificates +*/}} +{{- define "zookeeper.quorum.tlsSecretName" -}} +{{- $secretName := .Values.tls.quorum.existingSecret -}} +{{- if $secretName -}} + {{- printf "%s" (tpl $secretName $) -}} +{{- else -}} + {{- printf "%s-quorum-crt" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a secret containing the Keystore and Truststore password should be created for ZooKeeper quorum +*/}} +{{- define "zookeeper.quorum.createTlsPasswordsSecret" -}} +{{- if and .Values.tls.quorum.enabled (not .Values.tls.quorum.passwordsSecretName) }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret containing the Keystore and Truststore password +*/}} +{{- define "zookeeper.quorum.tlsPasswordsSecret" -}} +{{- $secretName := .Values.tls.quorum.passwordsSecretName -}} +{{- if $secretName -}} + {{- printf "%s" (tpl $secretName $) -}} +{{- else -}} + {{- printf "%s-quorum-tls-pass" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a TLS secret should be created for ZooKeeper client +*/}} +{{- define "zookeeper.client.createTlsSecret" -}} +{{- if and .Values.tls.client.enabled .Values.tls.client.autoGenerated (not .Values.tls.client.existingSecret) }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return the secret containing ZooKeeper client TLS certificates +*/}} +{{- define "zookeeper.client.tlsSecretName" -}} +{{- $secretName := .Values.tls.client.existingSecret -}} +{{- if $secretName -}} + {{- printf "%s" (tpl $secretName $) -}} +{{- else -}} + {{- printf "%s-client-crt" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Get the quorum keystore key to be retrieved from tls.quorum.existingSecret. +*/}} +{{- define "zookeeper.quorum.tlsKeystoreKey" -}} +{{- if and .Values.tls.quorum.existingSecret .Values.tls.quorum.existingSecretKeystoreKey -}} + {{- printf "%s" .Values.tls.quorum.existingSecretKeystoreKey -}} +{{- else -}} + {{- printf "zookeeper.keystore.jks" -}} +{{- end -}} +{{- end -}} + +{{/* +Get the quorum truststore key to be retrieved from tls.quorum.existingSecret. +*/}} +{{- define "zookeeper.quorum.tlsTruststoreKey" -}} +{{- if and .Values.tls.quorum.existingSecret .Values.tls.quorum.existingSecretTruststoreKey -}} + {{- printf "%s" .Values.tls.quorum.existingSecretTruststoreKey -}} +{{- else -}} + {{- printf "zookeeper.truststore.jks" -}} +{{- end -}} +{{- end -}} + +{{/* +Get the client keystore key to be retrieved from tls.client.existingSecret. +*/}} +{{- define "zookeeper.client.tlsKeystoreKey" -}} +{{- if and .Values.tls.client.existingSecret .Values.tls.client.existingSecretKeystoreKey -}} + {{- printf "%s" .Values.tls.client.existingSecretKeystoreKey -}} +{{- else -}} + {{- printf "zookeeper.keystore.jks" -}} +{{- end -}} +{{- end -}} + +{{/* +Get the client truststore key to be retrieved from tls.client.existingSecret. +*/}} +{{- define "zookeeper.client.tlsTruststoreKey" -}} +{{- if and .Values.tls.client.existingSecret .Values.tls.client.existingSecretTruststoreKey -}} + {{- printf "%s" .Values.tls.client.existingSecretTruststoreKey -}} +{{- else -}} + {{- printf "zookeeper.truststore.jks" -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a secret containing the Keystore and Truststore password should be created for ZooKeeper client +*/}} +{{- define "zookeeper.client.createTlsPasswordsSecret" -}} +{{- if and .Values.tls.client.enabled (not .Values.tls.client.passwordsSecretName) }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret containing the Keystore and Truststore password +*/}} +{{- define "zookeeper.client.tlsPasswordsSecret" -}} +{{- $secretName := .Values.tls.client.passwordsSecretName -}} +{{- if $secretName -}} + {{- printf "%s" (tpl $secretName $) -}} +{{- else -}} + {{- printf "%s-client-tls-pass" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Get the quorum keystore password key to be retrieved from tls.quorum.passwordSecretName. +*/}} +{{- define "zookeeper.quorum.tlsPasswordKeystoreKey" -}} +{{- if and .Values.tls.quorum.passwordsSecretName .Values.tls.quorum.passwordsSecretKeystoreKey -}} + {{- printf "%s" .Values.tls.quorum.passwordsSecretKeystoreKey -}} +{{- else -}} + {{- printf "keystore-password" -}} +{{- end -}} +{{- end -}} + +{{/* +Get the quorum truststore password key to be retrieved from tls.quorum.passwordSecretName. +*/}} +{{- define "zookeeper.quorum.tlsPasswordTruststoreKey" -}} +{{- if and .Values.tls.quorum.passwordsSecretName .Values.tls.quorum.passwordsSecretTruststoreKey -}} + {{- printf "%s" .Values.tls.quorum.passwordsSecretTruststoreKey -}} +{{- else -}} + {{- printf "truststore-password" -}} +{{- end -}} +{{- end -}} + +{{/* +Get the client keystore password key to be retrieved from tls.client.passwordSecretName. +*/}} +{{- define "zookeeper.client.tlsPasswordKeystoreKey" -}} +{{- if and .Values.tls.client.passwordsSecretName .Values.tls.client.passwordsSecretKeystoreKey -}} + {{- printf "%s" .Values.tls.client.passwordsSecretKeystoreKey -}} +{{- else -}} + {{- printf "keystore-password" -}} +{{- end -}} +{{- end -}} + +{{/* +Get the client truststore password key to be retrieved from tls.client.passwordSecretName. +*/}} +{{- define "zookeeper.client.tlsPasswordTruststoreKey" -}} +{{- if and .Values.tls.client.passwordsSecretName .Values.tls.client.passwordsSecretTruststoreKey -}} + {{- printf "%s" .Values.tls.client.passwordsSecretTruststoreKey -}} +{{- else -}} + {{- printf "truststore-password" -}} +{{- end -}} +{{- end -}} + +{{/* +Compile all warnings into a single message. +*/}} +{{- define "zookeeper.validateValues" -}} +{{- $messages := list -}} +{{- $messages := append $messages (include "zookeeper.validateValues.client.auth" .) -}} +{{- $messages := append $messages (include "zookeeper.validateValues.quorum.auth" .) -}} +{{- $messages := append $messages (include "zookeeper.validateValues.client.tls" .) -}} +{{- $messages := append $messages (include "zookeeper.validateValues.quorum.tls" .) -}} +{{- $messages := without $messages "" -}} +{{- $message := join "\n" $messages -}} + +{{- if $message -}} +{{- printf "\nVALUES VALIDATION:\n%s" $message | fail -}} +{{- end -}} +{{- end -}} + +{{/* +Validate values of ZooKeeper - Authentication enabled +*/}} +{{- define "zookeeper.validateValues.client.auth" -}} +{{- if and .Values.auth.client.enabled (not .Values.auth.client.existingSecret) (or (not .Values.auth.client.clientUser) (not .Values.auth.client.serverUsers)) }} +zookeeper: auth.client.enabled + In order to enable client-server authentication, you need to provide the list + of users to be created and the user to use for clients authentication. +{{- end -}} +{{- end -}} + +{{/* +Validate values of ZooKeeper - Authentication enabled +*/}} +{{- define "zookeeper.validateValues.quorum.auth" -}} +{{- if and .Values.auth.quorum.enabled (not .Values.auth.quorum.existingSecret) (or (not .Values.auth.quorum.learnerUser) (not .Values.auth.quorum.serverUsers)) }} +zookeeper: auth.quorum.enabled + In order to enable server-server authentication, you need to provide the list + of users to be created and the user to use for quorum authentication. +{{- end -}} +{{- end -}} + +{{/* +Validate values of ZooKeeper - Client TLS enabled +*/}} +{{- define "zookeeper.validateValues.client.tls" -}} +{{- if and .Values.tls.client.enabled (not .Values.tls.client.autoGenerated) (not .Values.tls.client.existingSecret) }} +zookeeper: tls.client.enabled + In order to enable Client TLS encryption, you also need to provide + an existing secret containing the Keystore and Truststore or + enable auto-generated certificates. +{{- end -}} +{{- end -}} + +{{/* +Validate values of ZooKeeper - Quorum TLS enabled +*/}} +{{- define "zookeeper.validateValues.quorum.tls" -}} +{{- if and .Values.tls.quorum.enabled (not .Values.tls.quorum.autoGenerated) (not .Values.tls.quorum.existingSecret) }} +zookeeper: tls.quorum.enabled + In order to enable Quorum TLS, you also need to provide + an existing secret containing the Keystore and Truststore or + enable auto-generated certificates. +{{- end -}} +{{- end -}} diff --git a/deployment/charts/kafka/charts/zookeeper/templates/configmap.yaml b/deployment/charts/kafka/charts/zookeeper/templates/configmap.yaml new file mode 100644 index 0000000..12b4f48 --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/templates/configmap.yaml @@ -0,0 +1,17 @@ +{{- if (include "zookeeper.createConfigmap" .) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "common.names.fullname" . }} + namespace: {{ template "zookeeper.namespace" . }} + 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 }} +data: + zoo.cfg: |- + {{- include "common.tplvalues.render" ( dict "value" .Values.configuration "context" $ ) | nindent 4 }} +{{- end }} diff --git a/deployment/deployment/middleware_deployment/redis-cluster/templates/extra-list.yaml b/deployment/charts/kafka/charts/zookeeper/templates/extra-list.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/redis-cluster/templates/extra-list.yaml rename to deployment/charts/kafka/charts/zookeeper/templates/extra-list.yaml diff --git a/deployment/charts/kafka/charts/zookeeper/templates/metrics-svc.yaml b/deployment/charts/kafka/charts/zookeeper/templates/metrics-svc.yaml new file mode 100644 index 0000000..5afc4b3 --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/templates/metrics-svc.yaml @@ -0,0 +1,29 @@ +{{- if .Values.metrics.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }}-metrics + namespace: {{ template "zookeeper.namespace" . }} + 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 or .Values.metrics.service.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.metrics.service.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.service.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: {{ .Values.metrics.service.type }} + ports: + - name: tcp-metrics + port: {{ .Values.metrics.service.port }} + targetPort: metrics + selector: {{- include "common.labels.matchLabels" . | nindent 4 }} + app.kubernetes.io/component: zookeeper +{{- end }} diff --git a/deployment/charts/kafka/charts/zookeeper/templates/networkpolicy.yaml b/deployment/charts/kafka/charts/zookeeper/templates/networkpolicy.yaml new file mode 100644 index 0000000..6353283 --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/templates/networkpolicy.yaml @@ -0,0 +1,41 @@ +{{- if .Values.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: {{ include "common.capabilities.networkPolicy.apiVersion" . }} +metadata: + name: {{ include "common.names.fullname" . }} + namespace: {{ template "zookeeper.namespace" . }} + 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.matchLabels" . | nindent 6 }} + policyTypes: + - Ingress + ingress: + # Allow inbound connections to ZooKeeper + - ports: + - port: {{ .Values.containerPorts.client }} + {{- if .Values.metrics.enabled }} + - port: {{ .Values.metrics.containerPort }} + {{- end }} + {{- if not .Values.networkPolicy.allowExternal }} + from: + - podSelector: + matchLabels: + {{ include "common.names.fullname" . }}-client: "true" + - podSelector: + matchLabels: {{- include "common.labels.matchLabels" . | nindent 14 }} + {{- end }} + # Allow internal communications between nodes + - ports: + - port: {{ .Values.containerPorts.follower }} + - port: {{ .Values.containerPorts.election }} + from: + - podSelector: + matchLabels: {{- include "common.labels.matchLabels" . | nindent 14 }} +{{- end }} diff --git a/deployment/charts/kafka/charts/zookeeper/templates/pdb.yaml b/deployment/charts/kafka/charts/zookeeper/templates/pdb.yaml new file mode 100644 index 0000000..f7faf65 --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/templates/pdb.yaml @@ -0,0 +1,26 @@ +{{- $replicaCount := int .Values.replicaCount }} +{{- if and .Values.pdb.create (gt $replicaCount 1) }} +apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ template "common.names.fullname" . }} + namespace: {{ template "zookeeper.namespace" . }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: zookeeper + {{- 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.pdb.minAvailable }} + minAvailable: {{ .Values.pdb.minAvailable }} + {{- end }} + {{- if .Values.pdb.maxUnavailable }} + maxUnavailable: {{ .Values.pdb.maxUnavailable }} + {{- end }} + selector: + matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: zookeeper +{{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/controller-prometheusrules.yaml b/deployment/charts/kafka/charts/zookeeper/templates/prometheusrule.yaml similarity index 53% rename from deployment/deployment/nginx-ingress-controller/templates/controller-prometheusrules.yaml rename to deployment/charts/kafka/charts/zookeeper/templates/prometheusrule.yaml index 4f07fc4..87dcd35 100644 --- a/deployment/deployment/nginx-ingress-controller/templates/controller-prometheusrules.yaml +++ b/deployment/charts/kafka/charts/zookeeper/templates/prometheusrule.yaml @@ -1,28 +1,27 @@ -{{- if and .Values.metrics.enabled .Values.metrics.prometheusRule.enabled }} +{{- if and .Values.metrics.enabled .Values.metrics.prometheusRule.enabled .Values.metrics.prometheusRule.rules }} apiVersion: monitoring.coreos.com/v1 kind: PrometheusRule metadata: name: {{ include "common.names.fullname" . }} {{- if .Values.metrics.prometheusRule.namespace }} - namespace: {{ .Values.metrics.prometheusRule.namespace | quote }} + namespace: {{ .Values.metrics.prometheusRule.namespace }} {{- else }} - namespace: {{ .Release.Namespace | quote }} + namespace: {{ .Release.Namespace }} {{- end }} labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: controller - {{- if .Values.metrics.prometheusRule.additionalLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.metrics.prometheusRule.additionalLabels "context" $) | nindent 4 }} - {{- end }} + app.kubernetes.io/component: metrics {{- if .Values.commonLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- 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: - {{- with .Values.metrics.prometheusRule.rules }} groups: - - name: {{ include "common.names.name" $ }} - rules: {{- toYaml . | nindent 6 }} - {{- end }} + - name: {{ include "common.names.fullname" . }} + rules: {{- toYaml .Values.metrics.prometheusRule.rules | nindent 8 }} {{- end }} + diff --git a/deployment/charts/kafka/charts/zookeeper/templates/scripts-configmap.yaml b/deployment/charts/kafka/charts/zookeeper/templates/scripts-configmap.yaml new file mode 100644 index 0000000..d0a7ddb --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/templates/scripts-configmap.yaml @@ -0,0 +1,102 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-scripts" (include "common.names.fullname" .) }} + namespace: {{ template "zookeeper.namespace" . }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: zookeeper + {{- 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: + init-certs.sh: |- + #!/bin/bash + + {{- if .Values.tls.client.enabled }} + if [[ -f "/certs/client/tls.key" ]] && [[ -f "/certs/client/tls.crt" ]] && [[ -f "/certs/client/ca.crt" ]]; then + if [[ -f "/opt/bitnami/zookeeper/config/certs/client/.initialized" ]]; then + exit 0 + fi + openssl pkcs12 -export -in "/certs/client/tls.crt" \ + -passout pass:"${ZOO_TLS_CLIENT_KEYSTORE_PASSWORD}" \ + -inkey "/certs/client/tls.key" \ + -out "/tmp/keystore.p12" + keytool -importkeystore -srckeystore "/tmp/keystore.p12" \ + -srcstoretype PKCS12 \ + -srcstorepass "${ZOO_TLS_CLIENT_KEYSTORE_PASSWORD}" \ + -deststorepass "${ZOO_TLS_CLIENT_KEYSTORE_PASSWORD}" \ + -destkeystore "/opt/bitnami/zookeeper/config/certs/client/zookeeper.keystore.jks" + rm "/tmp/keystore.p12" + keytool -import -file "/certs/client/ca.crt" \ + -keystore "/opt/bitnami/zookeeper/config/certs/client/zookeeper.truststore.jks" \ + -storepass "${ZOO_TLS_CLIENT_TRUSTSTORE_PASSWORD}" \ + -noprompt + touch /opt/bitnami/zookeeper/config/certs/client/.initialized + {{- if .Values.tls.client.autoGenerated }} + else + echo "Couldn't find the expected PEM certificates! They are mandatory when Client encryption via TLS is enabled." + exit 1 + fi + {{- else }} + elif [[ -f {{ printf "/certs/client/%s" (include "zookeeper.client.tlsTruststoreKey" .) | quote }} ]] && [[ -f {{ printf "/certs/client/%s" (include "zookeeper.client.tlsKeystoreKey" .) | quote }} ]]; then + cp {{ printf "/certs/client/%s" (include "zookeeper.client.tlsTruststoreKey" .) | quote }} "/opt/bitnami/zookeeper/config/certs/client/zookeeper.truststore.jks" + cp {{ printf "/certs/client/%s" (include "zookeeper.client.tlsKeystoreKey" .) | quote }} "/opt/bitnami/zookeeper/config/certs/client/zookeeper.keystore.jks" + else + echo "Couldn't find the expected Java Key Stores (JKS) files! They are mandatory when Client encryption via TLS is enabled." + exit 1 + fi + {{- end }} + {{- end }} + {{- if .Values.tls.quorum.enabled }} + if [[ -f "/certs/quorum/tls.key" ]] && [[ -f "/certs/quorum/tls.crt" ]] && [[ -f "/certs/quorum/ca.crt" ]]; then + openssl pkcs12 -export -in "/certs/quorum/tls.crt" \ + -passout pass:"${ZOO_TLS_QUORUM_KEYSTORE_PASSWORD}" \ + -inkey "/certs/quorum/tls.key" \ + -out "/tmp/keystore.p12" + keytool -importkeystore -srckeystore "/tmp/keystore.p12" \ + -srcstoretype PKCS12 \ + -srcstorepass "${ZOO_TLS_QUORUM_KEYSTORE_PASSWORD}" \ + -deststorepass "${ZOO_TLS_QUORUM_KEYSTORE_PASSWORD}" \ + -destkeystore "/opt/bitnami/zookeeper/config/certs/quorum/zookeeper.keystore.jks" + rm "/tmp/keystore.p12" + keytool -import -file "/certs/quorum/ca.crt" \ + -keystore "/opt/bitnami/zookeeper/config/certs/quorum/zookeeper.truststore.jks" \ + -storepass "${ZOO_TLS_QUORUM_TRUSTSTORE_PASSWORD}" \ + -noprompt + {{- if .Values.tls.quorum.autoGenerated }} + else + echo "Couldn't find the expected PEM certificates! They are mandatory when encryption Quorum via TLS is enabled." + exit 1 + fi + {{- else }} + elif [[ -f {{ printf "/certs/quorum/%s" (include "zookeeper.quorum.tlsTruststoreKey" .) | quote }} ]] && [[ -f {{ printf "/certs/quorum/%s" (include "zookeeper.quorum.tlsKeystoreKey" .) | quote }} ]]; then + cp {{ printf "/certs/quorum/%s" (include "zookeeper.quorum.tlsTruststoreKey" .) | quote }} "/opt/bitnami/zookeeper/config/certs/quorum/zookeeper.truststore.jks" + cp {{ printf "/certs/quorum/%s" (include "zookeeper.quorum.tlsKeystoreKey" .) | quote }} "/opt/bitnami/zookeeper/config/certs/quorum/zookeeper.keystore.jks" + else + echo "Couldn't find the expected Java Key Stores (JKS) files! They are mandatory when Quorum encryption via TLS is enabled." + exit 1 + fi + {{- end }} + {{- end }} + setup.sh: |- + #!/bin/bash + + # Execute entrypoint as usual after obtaining ZOO_SERVER_ID + # check ZOO_SERVER_ID in persistent volume via myid + # if not present, set based on POD hostname + if [[ -f "/bitnami/zookeeper/data/myid" ]]; then + export ZOO_SERVER_ID="$(cat /bitnami/zookeeper/data/myid)" + else + HOSTNAME="$(hostname -s)" + if [[ $HOSTNAME =~ (.*)-([0-9]+)$ ]]; then + ORD=${BASH_REMATCH[2]} + export ZOO_SERVER_ID="$((ORD + {{ .Values.minServerId }} ))" + else + echo "Failed to get index from hostname $HOST" + exit 1 + fi + fi + exec /entrypoint.sh /run.sh diff --git a/deployment/charts/kafka/charts/zookeeper/templates/secrets.yaml b/deployment/charts/kafka/charts/zookeeper/templates/secrets.yaml new file mode 100644 index 0000000..82ebc2e --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/templates/secrets.yaml @@ -0,0 +1,77 @@ +{{- if (include "zookeeper.client.createSecret" .) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ printf "%s-client-auth" (include "common.names.fullname" .) }} + namespace: {{ template "zookeeper.namespace" . }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: zookeeper + {{- 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: + client-password: {{ include "common.secrets.passwords.manage" (dict "secret" (printf "%s-client-auth" (include "common.names.fullname" .)) "key" "client-password" "providedValues" (list "auth.client.clientPassword") "context" $) }} + server-password: {{ include "common.secrets.passwords.manage" (dict "secret" (printf "%s-client-auth" (include "common.names.fullname" .)) "key" "server-password" "providedValues" (list "auth.client.serverPasswords") "context" $) }} +{{- end }} +{{- if (include "zookeeper.quorum.createSecret" .) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ printf "%s-quorum-auth" (include "common.names.fullname" .) }} + namespace: {{ template "zookeeper.namespace" . }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: zookeeper + {{- 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: + quorum-learner-password: {{ include "common.secrets.passwords.manage" (dict "secret" (printf "%s-quorum-auth" (include "common.names.fullname" .)) "key" "quorum-learner-password" "providedValues" (list "auth.quorum.learnerPassword") "context" $) }} + quorum-server-password: {{ include "common.secrets.passwords.manage" (dict "secret" (printf "%s-quorum-auth" (include "common.names.fullname" .)) "key" "quorum-server-password" "providedValues" (list "auth.quorum.serverPasswords") "context" $) }} +{{- end }} +{{- if (include "zookeeper.client.createTlsPasswordsSecret" .) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "common.names.fullname" . }}-client-tls-pass + namespace: {{ template "zookeeper.namespace" . }} + 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: + keystore-password: {{ default (randAlphaNum 10) .Values.tls.client.keystorePassword | b64enc | quote }} + truststore-password: {{ default (randAlphaNum 10) .Values.tls.client.truststorePassword | b64enc | quote }} +{{- end }} +{{- if (include "zookeeper.quorum.createTlsPasswordsSecret" .) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "common.names.fullname" . }}-quorum-tls-pass + namespace: {{ template "zookeeper.namespace" . }} + 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: + keystore-password: {{ default (randAlphaNum 10) .Values.tls.quorum.keystorePassword | b64enc | quote }} + truststore-password: {{ default (randAlphaNum 10) .Values.tls.quorum.truststorePassword | b64enc | quote }} +{{- end }} diff --git a/deployment/charts/kafka/charts/zookeeper/templates/serviceaccount.yaml b/deployment/charts/kafka/charts/zookeeper/templates/serviceaccount.yaml new file mode 100644 index 0000000..958a57a --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/templates/serviceaccount.yaml @@ -0,0 +1,21 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "zookeeper.serviceAccountName" . }} + namespace: {{ template "zookeeper.namespace" . }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: zookeeper + role: zookeeper + {{- 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.serviceAccount.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.serviceAccount.annotations "context" $ ) | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} +{{- end }} diff --git a/deployment/charts/kafka/charts/zookeeper/templates/servicemonitor.yaml b/deployment/charts/kafka/charts/zookeeper/templates/servicemonitor.yaml new file mode 100644 index 0000000..2c8af33 --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/templates/servicemonitor.yaml @@ -0,0 +1,53 @@ +{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "common.names.fullname" . }} + {{- if .Values.metrics.serviceMonitor.namespace }} + namespace: {{ .Values.metrics.serviceMonitor.namespace }} + {{- else }} + namespace: {{ .Release.Namespace }} + {{- end }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: metrics + {{- if .Values.metrics.serviceMonitor.additionalLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.additionalLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- 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.metrics.serviceMonitor.jobLabel }} + jobLabel: {{ .Values.metrics.serviceMonitor.jobLabel }} + {{- end }} + 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 }} + app.kubernetes.io/component: metrics + endpoints: + - port: tcp-metrics + path: "/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.relabelings }} + relabelings: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.relabelings "context" $) | nindent 6 }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.metricRelabelings }} + metricRelabelings: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.metricRelabelings "context" $) | nindent 6 }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.honorLabels }} + honorLabels: {{ .Values.metrics.serviceMonitor.honorLabels }} + {{- end }} + namespaceSelector: + matchNames: + - {{ template "zookeeper.namespace" . }} +{{- end }} diff --git a/deployment/charts/kafka/charts/zookeeper/templates/statefulset.yaml b/deployment/charts/kafka/charts/zookeeper/templates/statefulset.yaml new file mode 100644 index 0000000..025d363 --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/templates/statefulset.yaml @@ -0,0 +1,532 @@ +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ template "common.names.fullname" . }} + namespace: {{ template "zookeeper.namespace" . }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: zookeeper + role: zookeeper + {{- 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.replicaCount }} + podManagementPolicy: {{ .Values.podManagementPolicy }} + selector: + matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: zookeeper + serviceName: {{ printf "%s-headless" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }} + {{- if .Values.updateStrategy }} + updateStrategy: {{- toYaml .Values.updateStrategy | nindent 4 }} + {{- end }} + template: + metadata: + annotations: + {{- if .Values.podAnnotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.podAnnotations "context" $) | nindent 8 }} + {{- end }} + {{- if (include "zookeeper.createConfigmap" .) }} + checksum/configuration: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- end }} + {{- if or (include "zookeeper.quorum.createSecret" .) (include "zookeeper.client.createSecret" .) (include "zookeeper.client.createTlsPasswordsSecret" .) (include "zookeeper.quorum.createTlsPasswordsSecret" .) }} + checksum/secrets: {{ include (print $.Template.BasePath "/secrets.yaml") . | sha256sum }} + {{- end }} + {{- if or (include "zookeeper.client.createTlsSecret" .) (include "zookeeper.quorum.createTlsSecret" .) }} + checksum/tls-secrets: {{ include (print $.Template.BasePath "/tls-secrets.yaml") . | sha256sum }} + {{- end }} + labels: {{- include "common.labels.standard" . | nindent 8 }} + app.kubernetes.io/component: zookeeper + {{- if .Values.podLabels }} + {{- include "common.tplvalues.render" (dict "value" .Values.podLabels "context" $) | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ template "zookeeper.serviceAccountName" . }} + {{- include "zookeeper.imagePullSecrets" . | nindent 6 }} + {{- if .Values.hostAliases }} + hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.hostAliases "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAffinityPreset "component" "zookeeper" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset "component" "zookeeper" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.nodeAffinityPreset.type "key" .Values.nodeAffinityPreset.key "values" .Values.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.tolerations "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.topologySpreadConstraints }} + topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.topologySpreadConstraints "context" .) | nindent 8 }} + {{- end }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName }} + {{- end }} + {{- if .Values.schedulerName }} + schedulerName: {{ .Values.schedulerName }} + {{- end }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + initContainers: + {{- if and .Values.volumePermissions.enabled .Values.persistence.enabled }} + - name: volume-permissions + image: {{ template "zookeeper.volumePermissions.image" . }} + imagePullPolicy: {{ default "" .Values.volumePermissions.image.pullPolicy | quote }} + command: + - /bin/bash + args: + - -ec + - | + mkdir -p /bitnami/zookeeper + chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} /bitnami/zookeeper + find /bitnami/zookeeper -mindepth 1 -maxdepth 1 -not -name ".snapshot" -not -name "lost+found" | xargs -r chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} + {{- if .Values.dataLogDir }} + mkdir -p {{ .Values.dataLogDir }} + chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} {{ .Values.dataLogDir }} + find {{ .Values.dataLogDir }} -mindepth 1 -maxdepth 1 -not -name ".snapshot" -not -name "lost+found" | xargs -r chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} + {{- end }} + {{- if .Values.volumePermissions.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.volumePermissions.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.volumePermissions.resources }} + resources: {{- toYaml .Values.volumePermissions.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: /bitnami/zookeeper + {{- if .Values.dataLogDir }} + - name: data-log + mountPath: {{ .Values.dataLogDir }} + {{- end }} + {{- end }} + {{- if or .Values.tls.client.enabled .Values.tls.quorum.enabled }} + - name: init-certs + image: {{ include "zookeeper.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy | quote }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + command: + - /scripts/init-certs.sh + env: + - name: MY_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + {{- if or .Values.tls.client.passwordsSecretName (include "zookeeper.client.createTlsPasswordsSecret" .) }} + - name: ZOO_TLS_CLIENT_KEYSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "zookeeper.client.tlsPasswordsSecret" . }} + key: {{ include "zookeeper.client.tlsPasswordKeystoreKey" . }} + - name: ZOO_TLS_CLIENT_TRUSTSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "zookeeper.client.tlsPasswordsSecret" . }} + key: {{ include "zookeeper.client.tlsPasswordTruststoreKey" . }} + {{- end }} + {{- if or .Values.tls.quorum.passwordsSecretName (include "zookeeper.quorum.createTlsPasswordsSecret" .) }} + - name: ZOO_TLS_QUORUM_KEYSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "zookeeper.quorum.tlsPasswordsSecret" . }} + key: {{ include "zookeeper.quorum.tlsPasswordKeystoreKey" . }} + - name: ZOO_TLS_QUORUM_TRUSTSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "zookeeper.quorum.tlsPasswordsSecret" . }} + key: {{ include "zookeeper.quorum.tlsPasswordTruststoreKey" . }} + {{- end }} + {{- if .Values.tls.resources }} + resources: {{- toYaml .Values.tls.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: scripts + mountPath: /scripts/init-certs.sh + subPath: init-certs.sh + {{- if or .Values.tls.client.enabled }} + - name: client-certificates + mountPath: /certs/client + - name: client-shared-certs + mountPath: /opt/bitnami/zookeeper/config/certs/client + {{- end }} + {{- if or .Values.tls.quorum.enabled }} + - name: quorum-certificates + mountPath: /certs/quorum + - name: quorum-shared-certs + mountPath: /opt/bitnami/zookeeper/config/certs/quorum + {{- end }} + {{- end }} + {{- if .Values.initContainers }} + {{- include "common.tplvalues.render" (dict "value" .Values.initContainers "context" $) | trim | nindent 8 }} + {{- end }} + containers: + - name: zookeeper + image: {{ template "zookeeper.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy | quote }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.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.command }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.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.args }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.args "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.resources }} + resources: {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" (or .Values.image.debug .Values.diagnosticMode.enabled) | quote }} + - name: ZOO_DATA_LOG_DIR + value: {{ .Values.dataLogDir | quote }} + - name: ZOO_PORT_NUMBER + value: {{ .Values.containerPorts.client | quote }} + - name: ZOO_TICK_TIME + value: {{ .Values.tickTime | quote }} + - name: ZOO_INIT_LIMIT + value: {{ .Values.initLimit | quote }} + - name: ZOO_SYNC_LIMIT + value: {{ .Values.syncLimit | quote }} + - name: ZOO_PRE_ALLOC_SIZE + value: {{ .Values.preAllocSize | quote }} + - name: ZOO_SNAPCOUNT + value: {{ .Values.snapCount | quote }} + - name: ZOO_MAX_CLIENT_CNXNS + value: {{ .Values.maxClientCnxns | quote }} + - name: ZOO_4LW_COMMANDS_WHITELIST + value: {{ .Values.fourlwCommandsWhitelist | quote }} + - name: ZOO_LISTEN_ALLIPS_ENABLED + value: {{ ternary "yes" "no" .Values.listenOnAllIPs | quote }} + - name: ZOO_AUTOPURGE_INTERVAL + value: {{ .Values.autopurge.purgeInterval | quote }} + - name: ZOO_AUTOPURGE_RETAIN_COUNT + value: {{ .Values.autopurge.snapRetainCount | quote }} + - name: ZOO_MAX_SESSION_TIMEOUT + value: {{ .Values.maxSessionTimeout | quote }} + - name: ZOO_SERVERS + {{- $replicaCount := int .Values.replicaCount }} + {{- $minServerId := int .Values.minServerId }} + {{- $followerPort := int .Values.containerPorts.follower }} + {{- $electionPort := int .Values.containerPorts.election }} + {{- $releaseNamespace := include "zookeeper.namespace" . }} + {{- $zookeeperFullname := include "common.names.fullname" . }} + {{- $zookeeperHeadlessServiceName := printf "%s-%s" $zookeeperFullname "headless" | trunc 63 }} + {{- $clusterDomain := .Values.clusterDomain }} + value: {{ range $i, $e := until $replicaCount }}{{ $zookeeperFullname }}-{{ $e }}.{{ $zookeeperHeadlessServiceName }}.{{ $releaseNamespace }}.svc.{{ $clusterDomain }}:{{ $followerPort }}:{{ $electionPort }}::{{ add $e $minServerId }} {{ end }} + - name: ZOO_ENABLE_AUTH + value: {{ ternary "yes" "no" .Values.auth.client.enabled | quote }} + {{- if .Values.auth.client.enabled }} + - name: ZOO_CLIENT_USER + value: {{ .Values.auth.client.clientUser | quote }} + - name: ZOO_CLIENT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "zookeeper.client.secretName" . }} + key: client-password + - name: ZOO_SERVER_USERS + value: {{ .Values.auth.client.serverUsers | quote }} + - name: ZOO_SERVER_PASSWORDS + valueFrom: + secretKeyRef: + name: {{ include "zookeeper.client.secretName" . }} + key: server-password + {{- end }} + - name: ZOO_ENABLE_QUORUM_AUTH + value: {{ ternary "yes" "no" .Values.auth.quorum.enabled | quote }} + {{- if .Values.auth.quorum.enabled }} + - name: ZOO_QUORUM_LEARNER_USER + value: {{ .Values.auth.quorum.learnerUser | quote }} + - name: ZOO_QUORUM_LEARNER_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "zookeeper.quorum.secretName" . }} + key: quorum-learner-password + - name: ZOO_QUORUM_SERVER_USERS + value: {{ .Values.auth.quorum.serverUsers | quote }} + - name: ZOO_QUORUM_SERVER_PASSWORDS + valueFrom: + secretKeyRef: + name: {{ include "zookeeper.quorum.secretName" . }} + key: quorum-server-password + {{- end }} + - name: ZOO_HEAP_SIZE + value: {{ .Values.heapSize | quote }} + - name: ZOO_LOG_LEVEL + value: {{ .Values.logLevel | quote }} + - name: ALLOW_ANONYMOUS_LOGIN + value: {{ ternary "no" "yes" .Values.auth.client.enabled | quote }} + {{- if .Values.jvmFlags }} + - name: JVMFLAGS + value: {{ .Values.jvmFlags | quote }} + {{- end }} + {{- if .Values.metrics.enabled }} + - name: ZOO_ENABLE_PROMETHEUS_METRICS + value: "yes" + - name: ZOO_PROMETHEUS_METRICS_PORT_NUMBER + value: {{ .Values.metrics.containerPort | quote }} + {{- end }} + {{- if .Values.tls.client.enabled }} + - name: ZOO_TLS_PORT_NUMBER + value: {{ .Values.containerPorts.tls | quote }} + - name: ZOO_TLS_CLIENT_ENABLE + value: {{ .Values.tls.client.enabled | quote }} + - name: ZOO_TLS_CLIENT_AUTH + value: {{ .Values.tls.client.auth | quote }} + - name: ZOO_TLS_CLIENT_KEYSTORE_FILE + value: {{ .Values.tls.client.keystorePath | quote }} + - name: ZOO_TLS_CLIENT_TRUSTSTORE_FILE + value: {{ .Values.tls.client.truststorePath | quote }} + {{- if or .Values.tls.client.keystorePassword .Values.tls.client.passwordsSecretName .Values.tls.client.autoGenerated }} + - name: ZOO_TLS_CLIENT_KEYSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "zookeeper.client.tlsPasswordsSecret" . }} + key: {{ include "zookeeper.client.tlsPasswordKeystoreKey" . }} + {{- end }} + {{- if or .Values.tls.client.truststorePassword .Values.tls.client.passwordsSecretName .Values.tls.client.autoGenerated }} + - name: ZOO_TLS_CLIENT_TRUSTSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "zookeeper.client.tlsPasswordsSecret" . }} + key: {{ include "zookeeper.client.tlsPasswordTruststoreKey" . }} + {{- end }} + {{- end }} + {{- if .Values.tls.quorum.enabled }} + - name: ZOO_TLS_QUORUM_ENABLE + value: {{ .Values.tls.quorum.enabled | quote }} + - name: ZOO_TLS_QUORUM_CLIENT_AUTH + value: {{ .Values.tls.quorum.auth | quote }} + - name: ZOO_TLS_QUORUM_KEYSTORE_FILE + value: {{ .Values.tls.quorum.keystorePath | quote }} + - name: ZOO_TLS_QUORUM_TRUSTSTORE_FILE + value: {{ .Values.tls.quorum.truststorePath | quote }} + {{- if or .Values.tls.quorum.keystorePassword .Values.tls.quorum.passwordsSecretName .Values.tls.quorum.autoGenerated }} + - name: ZOO_TLS_QUORUM_KEYSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "zookeeper.quorum.tlsPasswordsSecret" . }} + key: {{ include "zookeeper.quorum.tlsPasswordKeystoreKey" . }} + {{- end }} + {{- if or .Values.tls.quorum.truststorePassword .Values.tls.quorum.passwordsSecretName .Values.tls.quorum.autoGenerated }} + - name: ZOO_TLS_QUORUM_TRUSTSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "zookeeper.quorum.tlsPasswordsSecret" . }} + key: {{ include "zookeeper.quorum.tlsPasswordTruststoreKey" . }} + {{- end }} + {{- end }} + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + {{- if .Values.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + {{- if or .Values.extraEnvVarsCM .Values.extraEnvVarsSecret }} + envFrom: + {{- if .Values.extraEnvVarsCM }} + - configMapRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsCM "context" $) }} + {{- end }} + {{- if .Values.extraEnvVarsSecret }} + - secretRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsSecret "context" $) }} + {{- end }} + {{- end }} + ports: + {{- if not .Values.service.disableBaseClientPort }} + - name: client + containerPort: {{ .Values.containerPorts.client }} + {{- end }} + {{- if .Values.tls.client.enabled }} + - name: client-tls + containerPort: {{ .Values.containerPorts.tls }} + {{- end }} + - name: follower + containerPort: {{ .Values.containerPorts.follower }} + - name: election + containerPort: {{ .Values.containerPorts.election }} + {{- if .Values.metrics.enabled }} + - name: metrics + containerPort: {{ .Values.metrics.containerPort }} + {{- end }} + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customLivenessProbe "context" $) | nindent 12 }} + {{- else if .Values.livenessProbe.enabled }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.livenessProbe "enabled" "probeCommandTimeout") "context" $) | nindent 12 }} + exec: + {{- if not .Values.service.disableBaseClientPort }} + command: ['/bin/bash', '-c', 'echo "ruok" | timeout {{ .Values.livenessProbe.probeCommandTimeout }} nc -w {{ .Values.livenessProbe.probeCommandTimeout }} localhost {{ .Values.containerPorts.client }} | grep imok'] + {{- else if not .Values.tls.client.enabled }} + command: ['/bin/bash', '-c', 'echo "ruok" | timeout {{ .Values.livenessProbe.probeCommandTimeout }} openssl s_client -quiet -crlf -connect localhost:{{ .Values.containerPorts.tls }} | grep imok'] + {{- else }} + command: ['/bin/bash', '-c', 'echo "ruok" | timeout {{ .Values.livenessProbe.probeCommandTimeout }} openssl s_client -quiet -crlf -connect localhost:{{ .Values.containerPorts.tls }} -cert {{ .Values.service.tls.client_cert_pem_path }} -key {{ .Values.service.tls.client_key_pem_path }} | grep imok'] + {{- end }} + {{- end }} + {{- if .Values.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 12 }} + {{- else if .Values.readinessProbe.enabled }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.readinessProbe "enabled" "probeCommandTimeout") "context" $) | nindent 12 }} + exec: + {{- if not .Values.service.disableBaseClientPort }} + command: ['/bin/bash', '-c', 'echo "ruok" | timeout {{ .Values.readinessProbe.probeCommandTimeout }} nc -w {{ .Values.readinessProbe.probeCommandTimeout }} localhost {{ .Values.containerPorts.client }} | grep imok'] + {{- else if not .Values.tls.client.enabled }} + command: ['/bin/bash', '-c', 'echo "ruok" | timeout {{ .Values.readinessProbe.probeCommandTimeout }} openssl s_client -quiet -crlf -connect localhost:{{ .Values.containerPorts.tls }} | grep imok'] + {{- else }} + command: ['/bin/bash', '-c', 'echo "ruok" | timeout {{ .Values.readinessProbe.probeCommandTimeout }} openssl s_client -quiet -crlf -connect localhost:{{ .Values.containerPorts.tls }} -cert {{ .Values.service.tls.client_cert_pem_path }} -key {{ .Values.service.tls.client_key_pem_path }} | grep imok'] + {{- end }} + {{- end }} + {{- if .Values.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.startupProbe.enabled }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.startupProbe "enabled") "context" $) | nindent 12 }} + tcpSocket: + {{- if not .Values.service.disableBaseClientPort }} + port: client + {{- else }} + port: follower + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.lifecycleHooks }} + lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.lifecycleHooks "context" $) | nindent 12 }} + {{- end }} + volumeMounts: + - name: scripts + mountPath: /scripts/setup.sh + subPath: setup.sh + - name: data + mountPath: /bitnami/zookeeper + {{- if .Values.dataLogDir }} + - name: data-log + mountPath: {{ .Values.dataLogDir }} + {{- end }} + {{- if or .Values.configuration .Values.existingConfigmap }} + - name: config + mountPath: /opt/bitnami/zookeeper/conf/zoo.cfg + subPath: zoo.cfg + {{- end }} + {{- if .Values.tls.client.enabled }} + - name: client-shared-certs + mountPath: /opt/bitnami/zookeeper/config/certs/client + readOnly: true + {{- end }} + {{- if .Values.tls.quorum.enabled }} + - name: quorum-shared-certs + mountPath: /opt/bitnami/zookeeper/config/certs/quorum + readOnly: true + {{- end }} + {{- if .Values.extraVolumeMounts }} + {{- include "common.tplvalues.render" ( dict "value" .Values.extraVolumeMounts "context" $ ) | nindent 12 }} + {{- end }} + {{- if .Values.sidecars }} + {{- include "common.tplvalues.render" ( dict "value" .Values.sidecars "context" $ ) | nindent 8 }} + {{- end }} + volumes: + - name: scripts + configMap: + name: {{ printf "%s-scripts" (include "common.names.fullname" .) }} + defaultMode: 0755 + {{- if or .Values.configuration .Values.existingConfigmap }} + - name: config + configMap: + name: {{ include "zookeeper.configmapName" . }} + {{- end }} + {{- if and .Values.persistence.enabled .Values.persistence.existingClaim }} + - name: data + persistentVolumeClaim: + claimName: {{ printf "%s" (tpl .Values.persistence.existingClaim .) }} + {{- else if not .Values.persistence.enabled }} + - name: data + emptyDir: {} + {{- end }} + {{- if and .Values.persistence.enabled .Values.persistence.dataLogDir.existingClaim }} + - name: data-log + persistentVolumeClaim: + claimName: {{ printf "%s" (tpl .Values.persistence.dataLogDir.existingClaim .) }} + {{- else if and ( not .Values.persistence.enabled ) .Values.dataLogDir }} + - name: data-log + emptyDir: {} + {{- end }} + {{- if .Values.tls.client.enabled }} + - name: client-certificates + secret: + secretName: {{ include "zookeeper.client.tlsSecretName" . }} + defaultMode: 256 + - name: client-shared-certs + emptyDir: {} + {{- end }} + {{- if .Values.tls.quorum.enabled }} + - name: quorum-certificates + secret: + secretName: {{ include "zookeeper.quorum.tlsSecretName" . }} + defaultMode: 256 + - name: quorum-shared-certs + emptyDir: {} + {{- end }} + {{- if .Values.extraVolumes }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraVolumes "context" $) | nindent 8 }} + {{- end }} + {{- if and .Values.persistence.enabled (not (and .Values.persistence.existingClaim .Values.persistence.dataLogDir.existingClaim) ) }} + volumeClaimTemplates: + {{- if not .Values.persistence.existingClaim }} + - metadata: + name: data + {{- if .Values.persistence.annotations }} + annotations: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.annotations "context" $) | nindent 10 }} + {{- end }} + {{- if .Values.persistence.labels }} + labels: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.labels "context" $) | nindent 10 }} + {{- end }} + spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{- include "common.storage.class" (dict "persistence" .Values.persistence "global" .Values.global) | nindent 8 }} + {{- if .Values.persistence.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.selector "context" $) | nindent 10 }} + {{- end }} + {{- end }} + {{- if and (not .Values.persistence.dataLogDir.existingClaim) .Values.dataLogDir }} + - metadata: + name: data-log + {{- if .Values.persistence.annotations }} + annotations: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.annotations "context" $) | nindent 10 }} + {{- end }} + {{- if .Values.persistence.labels }} + labels: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.labels "context" $) | nindent 10 }} + {{- end }} + spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.dataLogDir.size | quote }} + {{- include "common.storage.class" (dict "persistence" .Values.persistence "global" .Values.global) | nindent 8 }} + {{- if .Values.persistence.dataLogDir.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.dataLogDir.selector "context" $) | nindent 10 }} + {{- end }} + {{- end }} + {{- end }} diff --git a/deployment/charts/kafka/charts/zookeeper/templates/svc-headless.yaml b/deployment/charts/kafka/charts/zookeeper/templates/svc-headless.yaml new file mode 100644 index 0000000..ee05e1d --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/templates/svc-headless.yaml @@ -0,0 +1,42 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ printf "%s-headless" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }} + namespace: {{ template "zookeeper.namespace" . }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: zookeeper + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if or .Values.commonAnnotations .Values.service.headless.annotations }} + annotations: + {{- if .Values.service.headless.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.service.headless.annotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: ClusterIP + clusterIP: None + publishNotReadyAddresses: {{ .Values.service.headless.publishNotReadyAddresses }} + ports: + {{- if not .Values.service.disableBaseClientPort }} + - name: tcp-client + port: {{ .Values.service.ports.client }} + targetPort: client + {{- end }} + {{- if .Values.tls.client.enabled }} + - name: tcp-client-tls + port: {{ .Values.service.ports.tls }} + targetPort: client-tls + {{- end }} + - name: tcp-follower + port: {{ .Values.service.ports.follower }} + targetPort: follower + - name: tcp-election + port: {{ .Values.service.ports.election }} + targetPort: election + selector: {{- include "common.labels.matchLabels" . | nindent 4 }} + app.kubernetes.io/component: zookeeper diff --git a/deployment/charts/kafka/charts/zookeeper/templates/svc.yaml b/deployment/charts/kafka/charts/zookeeper/templates/svc.yaml new file mode 100644 index 0000000..6ad0b10 --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/templates/svc.yaml @@ -0,0 +1,71 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }} + namespace: {{ template "zookeeper.namespace" . }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: zookeeper + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if or .Values.commonAnnotations .Values.service.annotations }} + annotations: + {{- if .Values.service.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.service.annotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: {{ .Values.service.type }} + {{- if and .Values.service.clusterIP (eq .Values.service.type "ClusterIP") }} + clusterIP: {{ .Values.service.clusterIP }} + {{- end }} + {{- if or (eq .Values.service.type "LoadBalancer") (eq .Values.service.type "NodePort") }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy | quote }} + {{- end }} + {{- if and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerSourceRanges)) }} + loadBalancerSourceRanges: {{ .Values.service.loadBalancerSourceRanges }} + {{- end }} + {{- if and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerIP)) }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + {{- if .Values.service.sessionAffinity }} + sessionAffinity: {{ .Values.service.sessionAffinity }} + {{- end }} + {{- if .Values.service.sessionAffinityConfig }} + sessionAffinityConfig: {{- include "common.tplvalues.render" (dict "value" .Values.service.sessionAffinityConfig "context" $) | nindent 4 }} + {{- end }} + ports: + {{- if not .Values.service.disableBaseClientPort }} + - name: tcp-client + port: {{ .Values.service.ports.client }} + targetPort: client + {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.client)) }} + nodePort: {{ .Values.service.nodePorts.client }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + {{- end }} + {{- if .Values.tls.client.enabled }} + - name: tcp-client-tls + port: {{ .Values.service.ports.tls }} + targetPort: client-tls + {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.tls)) }} + nodePort: {{ .Values.service.nodePorts.tls }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + {{- end }} + - name: tcp-follower + port: {{ .Values.service.ports.follower }} + targetPort: follower + - name: tcp-election + port: {{ .Values.service.ports.election }} + targetPort: election + {{- if .Values.service.extraPorts }} + {{- include "common.tplvalues.render" (dict "value" .Values.service.extraPorts "context" $) | nindent 4 }} + {{- end }} + selector: {{- include "common.labels.matchLabels" . | nindent 4 }} + app.kubernetes.io/component: zookeeper diff --git a/deployment/charts/kafka/charts/zookeeper/templates/tls-secrets.yaml b/deployment/charts/kafka/charts/zookeeper/templates/tls-secrets.yaml new file mode 100644 index 0000000..a07480d --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/templates/tls-secrets.yaml @@ -0,0 +1,55 @@ +{{- if (include "zookeeper.client.createTlsSecret" .) }} +{{- $ca := genCA "zookeeper-client-ca" 365 }} +{{- $releaseNamespace := .Release.Namespace }} +{{- $clusterDomain := .Values.clusterDomain }} +{{- $fullname := include "common.names.fullname" . }} +{{- $serviceName := include "common.names.fullname" . }} +{{- $headlessServiceName := printf "%s-headless" (include "common.names.fullname" .) }} +{{- $altNames := list (printf "*.%s.%s.svc.%s" $headlessServiceName $releaseNamespace $clusterDomain) (printf "%s.%s.svc.%s" $headlessServiceName $releaseNamespace $clusterDomain) (printf "*.%s.%s.svc.%s" $serviceName $releaseNamespace $clusterDomain) (printf "%s.%s.svc.%s" $serviceName $releaseNamespace $clusterDomain) "127.0.0.1" "localhost" $fullname }} +{{- $crt := genSignedCert $fullname nil $altNames 365 $ca }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "common.names.fullname" . }}-client-crt + namespace: {{ template "zookeeper.namespace" . }} + 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: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $crt.Cert | b64enc | quote }} + tls.key: {{ $crt.Key | b64enc | quote }} +{{- end }} +{{- if (include "zookeeper.quorum.createTlsSecret" .) }} +{{- $ca := genCA "zookeeper-quorum-ca" 365 }} +{{- $releaseNamespace := .Release.Namespace }} +{{- $clusterDomain := .Values.clusterDomain }} +{{- $fullname := include "common.names.fullname" . }} +{{- $serviceName := include "common.names.fullname" . }} +{{- $headlessServiceName := printf "%s-headless" (include "common.names.fullname" .) }} +{{- $altNames := list (printf "*.%s.%s.svc.%s" $headlessServiceName $releaseNamespace $clusterDomain) (printf "%s.%s.svc.%s" $headlessServiceName $releaseNamespace $clusterDomain) (printf "*.%s.%s.svc.%s" $serviceName $releaseNamespace $clusterDomain) (printf "%s.%s.svc.%s" $serviceName $releaseNamespace $clusterDomain) $fullname }} +{{- $crt := genSignedCert $fullname nil $altNames 365 $ca }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "common.names.fullname" . }}-quorum-crt + namespace: {{ template "zookeeper.namespace" . }} + 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: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $crt.Cert | b64enc | quote }} + tls.key: {{ $crt.Key | b64enc | quote }} +{{- end }} diff --git a/deployment/charts/kafka/charts/zookeeper/values.yaml b/deployment/charts/kafka/charts/zookeeper/values.yaml new file mode 100644 index 0000000..9343832 --- /dev/null +++ b/deployment/charts/kafka/charts/zookeeper/values.yaml @@ -0,0 +1,877 @@ +## @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 StorageClass for Persistent Volume(s) +## +global: + imageRegistry: "" + ## E.g. + ## imagePullSecrets: + ## - myRegistryKeySecretName + ## + imagePullSecrets: [] + storageClass: "" + +## @section Common parameters +## + +## @param kubeVersion Override Kubernetes version +## +kubeVersion: "" +## @param nameOverride String to partially override common.names.fullname template (will maintain the release name) +## +nameOverride: "" +## @param fullnameOverride String to fully override common.names.fullname template +## +fullnameOverride: "" +## @param clusterDomain Kubernetes Cluster Domain +## +clusterDomain: cluster.local +## @param extraDeploy Extra objects to deploy (evaluated as a template) +## +extraDeploy: [] +## @param commonLabels Add labels to all the deployed resources +## +commonLabels: {} +## @param commonAnnotations Add annotations to all the deployed resources +## +commonAnnotations: {} +## @param namespaceOverride Override namespace for ZooKeeper resources +## Useful when including ZooKeeper as a chart dependency, so it can be released into a different namespace than the parent +## +namespaceOverride: "" + +## Enable diagnostic mode in the statefulset +## +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 statefulset + ## + command: + - sleep + ## @param diagnosticMode.args Args to override all containers in the statefulset + ## + args: + - infinity + +## @section ZooKeeper chart parameters + +## Bitnami ZooKeeper image version +## ref: https://hub.docker.com/r/bitnami/zookeeper/tags/ +## @param image.registry ZooKeeper image registry +## @param image.repository ZooKeeper image repository +## @param image.tag ZooKeeper image tag (immutable tags are recommended) +## @param image.digest ZooKeeper image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag +## @param image.pullPolicy ZooKeeper image pull policy +## @param image.pullSecrets Specify docker-registry secret names as an array +## @param image.debug Specify if debug values should be set +## +image: + registry: docker.io + repository: bitnami/zookeeper + tag: 3.8.0-debian-11-r65 + 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 + ## + debug: false +## Authentication parameters +## +auth: + client: + ## @param auth.client.enabled Enable ZooKeeper client-server authentication. It uses SASL/Digest-MD5 + ## + enabled: false + ## @param auth.client.clientUser User that will use ZooKeeper clients to auth + ## + clientUser: "" + ## @param auth.client.clientPassword Password that will use ZooKeeper clients to auth + ## + clientPassword: "" + ## @param auth.client.serverUsers Comma, semicolon or whitespace separated list of user to be created + ## Specify them as a string, for example: "user1,user2,admin" + ## + serverUsers: "" + ## @param auth.client.serverPasswords Comma, semicolon or whitespace separated list of passwords to assign to users when created + ## Specify them as a string, for example: "pass4user1, pass4user2, pass4admin" + ## + serverPasswords: "" + ## @param auth.client.existingSecret Use existing secret (ignores previous passwords) + ## + existingSecret: "" + quorum: + ## @param auth.quorum.enabled Enable ZooKeeper server-server authentication. It uses SASL/Digest-MD5 + ## + enabled: false + ## @param auth.quorum.learnerUser User that the ZooKeeper quorumLearner will use to authenticate to quorumServers. + ## Note: Make sure the user is included in auth.quorum.serverUsers + ## + learnerUser: "" + ## @param auth.quorum.learnerPassword Password that the ZooKeeper quorumLearner will use to authenticate to quorumServers. + ## + learnerPassword: "" + ## @param auth.quorum.serverUsers Comma, semicolon or whitespace separated list of users for the quorumServers. + ## Specify them as a string, for example: "user1,user2,admin" + ## + serverUsers: "" + ## @param auth.quorum.serverPasswords Comma, semicolon or whitespace separated list of passwords to assign to users when created + ## Specify them as a string, for example: "pass4user1, pass4user2, pass4admin" + ## + serverPasswords: "" + ## @param auth.quorum.existingSecret Use existing secret (ignores previous passwords) + ## + existingSecret: "" +## @param tickTime Basic time unit (in milliseconds) used by ZooKeeper for heartbeats +## +tickTime: 2000 +## @param initLimit ZooKeeper uses to limit the length of time the ZooKeeper servers in quorum have to connect to a leader +## +initLimit: 10 +## @param syncLimit How far out of date a server can be from a leader +## +syncLimit: 5 +## @param preAllocSize Block size for transaction log file +## +preAllocSize: 65536 +## @param snapCount The number of transactions recorded in the transaction log before a snapshot can be taken (and the transaction log rolled) +## +snapCount: 100000 +## @param maxClientCnxns Limits the number of concurrent connections that a single client may make to a single member of the ZooKeeper ensemble +## +maxClientCnxns: 60 +## @param maxSessionTimeout Maximum session timeout (in milliseconds) that the server will allow the client to negotiate +## Defaults to 20 times the tickTime +## +maxSessionTimeout: 40000 +## @param heapSize Size (in MB) for the Java Heap options (Xmx and Xms) +## This env var is ignored if Xmx an Xms are configured via `jvmFlags` +## +heapSize: 1024 +## @param fourlwCommandsWhitelist A list of comma separated Four Letter Words commands that can be executed +## +fourlwCommandsWhitelist: srvr, mntr, ruok +## @param minServerId Minimal SERVER_ID value, nodes increment their IDs respectively +## Servers increment their ID starting at this minimal value. +## E.g., with `minServerId=10` and 3 replicas, server IDs will be 10, 11, 12 for z-0, z-1 and z-2 respectively. +## +minServerId: 1 +## @param listenOnAllIPs Allow ZooKeeper to listen for connections from its peers on all available IP addresses +## +listenOnAllIPs: false +## Ongoing data directory cleanup configuration +## +autopurge: + ## @param autopurge.snapRetainCount The most recent snapshots amount (and corresponding transaction logs) to retain + ## + snapRetainCount: 3 + ## @param autopurge.purgeInterval The time interval (in hours) for which the purge task has to be triggered + ## Set to a positive integer to enable the auto purging + ## + purgeInterval: 0 +## @param logLevel Log level for the ZooKeeper server. ERROR by default +## Have in mind if you set it to INFO or WARN the ReadinessProve will produce a lot of logs +## +logLevel: ERROR +## @param jvmFlags Default JVM flags for the ZooKeeper process +## +jvmFlags: "" +## @param dataLogDir Dedicated data log directory +## This allows a dedicated log device to be used, and helps avoid competition between logging and snapshots. +## E.g. +## dataLogDir: /bitnami/zookeeper/dataLog +## +dataLogDir: "" +## @param configuration Configure ZooKeeper with a custom zoo.cfg file +## e.g: +## configuration: |- +## deploy-working-dir=/bitnami/geode/data +## log-level=info +## ... +## +configuration: "" +## @param existingConfigmap The name of an existing ConfigMap with your custom configuration for ZooKeeper +## NOTE: When it's set the `configuration` parameter is ignored +## +existingConfigmap: "" +## @param extraEnvVars Array with extra environment variables to add to ZooKeeper nodes +## e.g: +## extraEnvVars: +## - name: FOO +## value: "bar" +## +extraEnvVars: [] +## @param extraEnvVarsCM Name of existing ConfigMap containing extra env vars for ZooKeeper nodes +## +extraEnvVarsCM: "" +## @param extraEnvVarsSecret Name of existing Secret containing extra env vars for ZooKeeper nodes +## +extraEnvVarsSecret: "" +## @param command Override default container command (useful when using custom images) +## +command: + - /scripts/setup.sh +## @param args Override default container args (useful when using custom images) +## +args: [] + +## @section Statefulset parameters + +## @param replicaCount Number of ZooKeeper nodes +## +replicaCount: 1 +## @param containerPorts.client ZooKeeper client container port +## @param containerPorts.tls ZooKeeper TLS container port +## @param containerPorts.follower ZooKeeper follower container port +## @param containerPorts.election ZooKeeper election container port +## +containerPorts: + client: 2181 + tls: 3181 + follower: 2888 + election: 3888 +## Configure extra options for ZooKeeper containers' liveness, readiness and startup probes +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes +## @param livenessProbe.enabled Enable livenessProbe on ZooKeeper containers +## @param livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe +## @param livenessProbe.periodSeconds Period seconds for livenessProbe +## @param livenessProbe.timeoutSeconds Timeout seconds for livenessProbe +## @param livenessProbe.failureThreshold Failure threshold for livenessProbe +## @param livenessProbe.successThreshold Success threshold for livenessProbe +## @param livenessProbe.probeCommandTimeout Probe command timeout for livenessProbe +## +livenessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + probeCommandTimeout: 2 +## @param readinessProbe.enabled Enable readinessProbe on ZooKeeper containers +## @param readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe +## @param readinessProbe.periodSeconds Period seconds for readinessProbe +## @param readinessProbe.timeoutSeconds Timeout seconds for readinessProbe +## @param readinessProbe.failureThreshold Failure threshold for readinessProbe +## @param readinessProbe.successThreshold Success threshold for readinessProbe +## @param readinessProbe.probeCommandTimeout Probe command timeout for readinessProbe +## +readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + probeCommandTimeout: 2 +## @param startupProbe.enabled Enable startupProbe on ZooKeeper containers +## @param startupProbe.initialDelaySeconds Initial delay seconds for startupProbe +## @param startupProbe.periodSeconds Period seconds for startupProbe +## @param startupProbe.timeoutSeconds Timeout seconds for startupProbe +## @param startupProbe.failureThreshold Failure threshold for startupProbe +## @param startupProbe.successThreshold Success threshold for startupProbe +## +startupProbe: + enabled: false + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 15 + successThreshold: 1 +## @param customLivenessProbe Custom livenessProbe that overrides the default one +## +customLivenessProbe: {} +## @param customReadinessProbe Custom readinessProbe that overrides the default one +## +customReadinessProbe: {} +## @param customStartupProbe Custom startupProbe that overrides the default one +## +customStartupProbe: {} +## @param lifecycleHooks for the ZooKeeper container(s) to automate configuration before or after startup +## +lifecycleHooks: {} +## ZooKeeper resource requests and limits +## ref: https://kubernetes.io/docs/user-guide/compute-resources/ +## @param resources.limits The resources limits for the ZooKeeper containers +## @param resources.requests.memory The requested memory for the ZooKeeper containers +## @param resources.requests.cpu The requested cpu for the ZooKeeper containers +## +resources: + limits: {} + requests: + memory: 256Mi + cpu: 250m +## Configure Pods Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod +## @param podSecurityContext.enabled Enabled ZooKeeper pods' Security Context +## @param podSecurityContext.fsGroup Set ZooKeeper pod's Security Context fsGroup +## +podSecurityContext: + enabled: true + fsGroup: 1001 +## Configure Container Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container +## @param containerSecurityContext.enabled Enabled ZooKeeper containers' Security Context +## @param containerSecurityContext.runAsUser Set ZooKeeper containers' Security Context runAsUser +## @param containerSecurityContext.runAsNonRoot Set ZooKeeper containers' Security Context runAsNonRoot +## @param containerSecurityContext.allowPrivilegeEscalation Force the child process to be run as nonprivilege +## +containerSecurityContext: + enabled: true + runAsUser: 1001 + runAsNonRoot: true + allowPrivilegeEscalation: false +## @param hostAliases ZooKeeper pods host aliases +## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ +## +hostAliases: [] +## @param podLabels Extra labels for ZooKeeper pods +## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ +## +podLabels: {} +## @param podAnnotations Annotations for ZooKeeper pods +## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ +## +podAnnotations: {} +## @param podAffinityPreset Pod affinity preset. Ignored if `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 podAntiAffinityPreset Pod anti-affinity preset. Ignored if `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 +## Node affinity preset +## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity +## +nodeAffinityPreset: + ## @param nodeAffinityPreset.type Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` + ## + type: "" + ## @param nodeAffinityPreset.key Node label key to match Ignored if `affinity` is set. + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## @param nodeAffinityPreset.values Node label values to match. Ignored if `affinity` is set. + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] +## @param affinity Affinity for pod 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 nodeSelector Node labels for pod assignment +## Ref: https://kubernetes.io/docs/user-guide/node-selection/ +## +nodeSelector: {} +## @param tolerations Tolerations for pod assignment +## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ +## +tolerations: [] +## @param topologySpreadConstraints Topology Spread Constraints for pod assignment spread across your cluster among failure-domains. Evaluated as a template +## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#spread-constraints-for-pods +## +topologySpreadConstraints: [] +## @param podManagementPolicy StatefulSet controller supports relax its ordering guarantees while preserving its uniqueness and identity guarantees. There are two valid pod management policies: `OrderedReady` and `Parallel` +## ref: https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/#pod-management-policy +## +podManagementPolicy: Parallel +## @param priorityClassName Name of the existing priority class to be used by ZooKeeper pods, priority class needs to be created beforehand +## Ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ +## +priorityClassName: "" +## @param schedulerName Kubernetes pod scheduler registry +## https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ +## +schedulerName: "" +## @param updateStrategy.type ZooKeeper statefulset strategy type +## @param updateStrategy.rollingUpdate ZooKeeper statefulset rolling update configuration parameters +## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies +## +updateStrategy: + type: RollingUpdate + rollingUpdate: {} +## @param extraVolumes Optionally specify extra list of additional volumes for the ZooKeeper pod(s) +## Example Use Case: mount certificates to enable TLS +## e.g: +## extraVolumes: +## - name: zookeeper-keystore +## secret: +## defaultMode: 288 +## secretName: zookeeper-keystore +## - name: zookeeper-truststore +## secret: +## defaultMode: 288 +## secretName: zookeeper-truststore +## +extraVolumes: [] +## @param extraVolumeMounts Optionally specify extra list of additional volumeMounts for the ZooKeeper container(s) +## Example Use Case: mount certificates to enable TLS +## e.g: +## extraVolumeMounts: +## - name: zookeeper-keystore +## mountPath: /certs/keystore +## readOnly: true +## - name: zookeeper-truststore +## mountPath: /certs/truststore +## readOnly: true +## +extraVolumeMounts: [] +## @param sidecars Add additional sidecar containers to the ZooKeeper pod(s) +## e.g: +## sidecars: +## - name: your-image-name +## image: your-image +## imagePullPolicy: Always +## ports: +## - name: portname +## containerPort: 1234 +## +sidecars: [] +## @param initContainers Add additional init containers to the ZooKeeper pod(s) +## Example: +## initContainers: +## - name: your-image-name +## image: your-image +## imagePullPolicy: Always +## ports: +## - name: portname +## containerPort: 1234 +## +initContainers: [] +## ZooKeeper Pod Disruption Budget +## ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ +## @param pdb.create Deploy a pdb object for the ZooKeeper pod +## @param pdb.minAvailable Minimum available ZooKeeper replicas +## @param pdb.maxUnavailable Maximum unavailable ZooKeeper replicas +## +pdb: + create: false + minAvailable: "" + maxUnavailable: 1 + +## @section Traffic Exposure parameters + +service: + ## @param service.type Kubernetes Service type + ## + type: ClusterIP + ## @param service.ports.client ZooKeeper client service port + ## @param service.ports.tls ZooKeeper TLS service port + ## @param service.ports.follower ZooKeeper follower service port + ## @param service.ports.election ZooKeeper election service port + ## + ports: + client: 2181 + tls: 3181 + follower: 2888 + election: 3888 + ## Node ports to expose + ## NOTE: choose port between <30000-32767> + ## @param service.nodePorts.client Node port for clients + ## @param service.nodePorts.tls Node port for TLS + ## + nodePorts: + client: "" + tls: "" + ## @param service.disableBaseClientPort Remove client port from service definitions. + ## + disableBaseClientPort: false + ## @param service.sessionAffinity Control where client requests go, to the same pod or round-robin + ## Values: ClientIP or None + ## ref: https://kubernetes.io/docs/user-guide/services/ + ## + sessionAffinity: None + ## @param service.sessionAffinityConfig Additional settings for the sessionAffinity + ## sessionAffinityConfig: + ## clientIP: + ## timeoutSeconds: 300 + ## + sessionAffinityConfig: {} + ## @param service.clusterIP ZooKeeper service Cluster IP + ## e.g.: + ## clusterIP: None + ## + clusterIP: "" + ## @param service.loadBalancerIP ZooKeeper service Load Balancer IP + ## ref: https://kubernetes.io/docs/user-guide/services/#type-loadbalancer + ## + loadBalancerIP: "" + ## @param service.loadBalancerSourceRanges ZooKeeper service Load Balancer sources + ## ref: 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 service.externalTrafficPolicy ZooKeeper service external traffic policy + ## ref https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + ## + externalTrafficPolicy: Cluster + ## @param service.annotations Additional custom annotations for ZooKeeper service + ## + annotations: {} + ## @param service.extraPorts Extra ports to expose in the ZooKeeper service (normally used with the `sidecar` value) + ## + extraPorts: [] + ## @param service.headless.annotations Annotations for the Headless Service + ## @param service.headless.publishNotReadyAddresses If the ZooKeeper headless service should publish DNS records for not ready pods + ## + headless: + publishNotReadyAddresses: true + annotations: {} +## Network policies +## Ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ +## +networkPolicy: + ## @param networkPolicy.enabled Specifies whether a NetworkPolicy should be created + ## + enabled: false + ## @param networkPolicy.allowExternal Don't require client label for connections + ## When set to false, only pods with the correct client label will have network access to the port Redis® is + ## listening on. When true, zookeeper accept connections from any source (with the correct destination port). + ## + allowExternal: true + +## @section Other Parameters + +## Service account for ZooKeeper to use. +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +## +serviceAccount: + ## @param serviceAccount.create Enable creation of ServiceAccount for ZooKeeper pod + ## + create: false + ## @param serviceAccount.name The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the common.names.fullname template + ## + name: "" + ## @param serviceAccount.automountServiceAccountToken Allows auto mount of ServiceAccountToken on the serviceAccount created + ## Can be set to false if pods using this serviceAccount do not need to use K8s API + ## + automountServiceAccountToken: true + ## @param serviceAccount.annotations Additional custom annotations for the ServiceAccount + ## + annotations: {} + +## @section Persistence parameters + +## Enable persistence using Persistent Volume Claims +## ref: https://kubernetes.io/docs/user-guide/persistent-volumes/ +## +persistence: + ## @param persistence.enabled Enable ZooKeeper data persistence using PVC. If false, use emptyDir + ## + enabled: true + ## @param persistence.existingClaim Name of an existing PVC to use (only when deploying a single replica) + ## + existingClaim: "" + ## @param persistence.storageClass PVC Storage Class for ZooKeeper data volume + ## 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 persistence.accessModes PVC Access modes + ## + accessModes: + - ReadWriteOnce + ## @param persistence.size PVC Storage Request for ZooKeeper data volume + ## + size: 8Gi + ## @param persistence.annotations Annotations for the PVC + ## + annotations: {} + ## @param persistence.labels Labels for the PVC + ## + labels: {} + ## @param persistence.selector Selector to match an existing Persistent Volume for ZooKeeper's data PVC + ## If set, the PVC can't have a PV dynamically provisioned for it + ## E.g. + ## selector: + ## matchLabels: + ## app: my-app + ## + selector: {} + ## Persistence for a dedicated data log directory + ## + dataLogDir: + ## @param persistence.dataLogDir.size PVC Storage Request for ZooKeeper's dedicated data log directory + ## + size: 8Gi + ## @param persistence.dataLogDir.existingClaim Provide an existing `PersistentVolumeClaim` for ZooKeeper's data log directory + ## If defined, PVC must be created manually before volume will be bound + ## The value is evaluated as a template + ## + existingClaim: "" + ## @param persistence.dataLogDir.selector Selector to match an existing Persistent Volume for ZooKeeper's data log PVC + ## If set, the PVC can't have a PV dynamically provisioned for it + ## E.g. + ## selector: + ## matchLabels: + ## app: my-app + ## + selector: {} + +## @section Volume Permissions parameters +## + +## Init containers parameters: +## volumePermissions: Change the owner and group of the persistent volume(s) mountpoint(s) to 'runAsUser:fsGroup' on each node +## +volumePermissions: + ## @param volumePermissions.enabled Enable init container that changes the owner and group of the persistent volume + ## + 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 Init container volume-permissions image pull secrets + ## + image: + registry: docker.io + repository: bitnami/bitnami-shell + tag: 11-debian-11-r60 + 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: [] + ## Init container resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## @param volumePermissions.resources.limits Init container volume-permissions resource limits + ## @param volumePermissions.resources.requests Init container volume-permissions resource requests + ## + resources: + limits: {} + requests: {} + ## Init container' Security Context + ## Note: the chown of the data folder is done to containerSecurityContext.runAsUser + ## and not the below volumePermissions.containerSecurityContext.runAsUser + ## @param volumePermissions.containerSecurityContext.enabled Enabled init container Security Context + ## @param volumePermissions.containerSecurityContext.runAsUser User ID for the init container + ## + containerSecurityContext: + enabled: true + runAsUser: 0 + +## @section Metrics parameters +## + +## ZooKeeper Prometheus Exporter configuration +## +metrics: + ## @param metrics.enabled Enable Prometheus to access ZooKeeper metrics endpoint + ## + enabled: false + ## @param metrics.containerPort ZooKeeper Prometheus Exporter container port + ## + containerPort: 9141 + ## Service configuration + ## + service: + ## @param metrics.service.type ZooKeeper Prometheus Exporter service type + ## + type: ClusterIP + ## @param metrics.service.port ZooKeeper Prometheus Exporter service port + ## + port: 9141 + ## @param metrics.service.annotations [object] Annotations for Prometheus to auto-discover the metrics endpoint + ## + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "{{ .Values.metrics.service.port }}" + prometheus.io/path: "/metrics" + ## Prometheus Operator ServiceMonitor configuration + ## + serviceMonitor: + ## @param metrics.serviceMonitor.enabled Create ServiceMonitor Resource for scraping metrics using Prometheus Operator + ## + enabled: false + ## @param metrics.serviceMonitor.namespace Namespace for the ServiceMonitor Resource (defaults to the Release Namespace) + ## + namespace: "" + ## @param metrics.serviceMonitor.interval Interval at which metrics should be scraped. + ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#endpoint + ## + interval: "" + ## @param metrics.serviceMonitor.scrapeTimeout Timeout after which the scrape is ended + ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#endpoint + ## + scrapeTimeout: "" + ## @param metrics.serviceMonitor.additionalLabels Additional labels that can be used so ServiceMonitor will be discovered by Prometheus + ## + additionalLabels: {} + ## @param metrics.serviceMonitor.selector Prometheus instance selector labels + ## ref: https://github.com/bitnami/charts/tree/main/bitnami/prometheus-operator#prometheus-configuration + ## + selector: {} + ## @param metrics.serviceMonitor.relabelings RelabelConfigs to apply to samples before scraping + ## + relabelings: [] + ## @param metrics.serviceMonitor.metricRelabelings MetricRelabelConfigs to apply to samples before ingestion + ## + metricRelabelings: [] + ## @param metrics.serviceMonitor.honorLabels Specify honorLabels parameter to add the scrape endpoint + ## + honorLabels: false + ## @param metrics.serviceMonitor.jobLabel The name of the label on the target service to use as the job name in prometheus. + ## + jobLabel: "" + ## Prometheus Operator PrometheusRule configuration + ## + prometheusRule: + ## @param metrics.prometheusRule.enabled Create a PrometheusRule for Prometheus Operator + ## + 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 PrometheusRule definitions + ## - alert: ZooKeeperSyncedFollowers + ## annotations: + ## message: The number of synced followers for the leader node in ZooKeeper deployment my-release is less than 2. This usually means that some of the ZooKeeper nodes aren't communicating properly. If it doesn't resolve itself you can try killing the pods (one by one). + ## expr: max(synced_followers{service="my-release-metrics"}) < 2 + ## for: 5m + ## labels: + ## severity: critical + ## - alert: ZooKeeperOutstandingRequests + ## annotations: + ## message: The number of outstanding requests for ZooKeeper pod {{ $labels.pod }} is greater than 10. This can indicate a performance issue with the Pod or cluster a whole. + ## expr: outstanding_requests{service="my-release-metrics"} > 10 + ## for: 5m + ## labels: + ## severity: critical + ## + rules: [] + +## @section TLS/SSL parameters +## + +## Enable SSL/TLS encryption +## +tls: + client: + ## @param tls.client.enabled Enable TLS for client connections + ## + enabled: false + ## @param tls.client.auth SSL Client auth. Can be "none", "want" or "need". + ## + auth: "none" + ## @param tls.client.autoGenerated Generate automatically self-signed TLS certificates for ZooKeeper client communications + ## Currently only supports PEM certificates + ## + autoGenerated: false + ## @param tls.client.existingSecret Name of the existing secret containing the TLS certificates for ZooKeeper client communications + ## + existingSecret: "" + ## @param tls.client.existingSecretKeystoreKey The secret key from the tls.client.existingSecret containing the Keystore. + ## + existingSecretKeystoreKey: "" + ## @param tls.client.existingSecretTruststoreKey The secret key from the tls.client.existingSecret containing the Truststore. + ## + existingSecretTruststoreKey: "" + ## @param tls.client.keystorePath Location of the KeyStore file used for Client connections + ## + keystorePath: /opt/bitnami/zookeeper/config/certs/client/zookeeper.keystore.jks + ## @param tls.client.truststorePath Location of the TrustStore file used for Client connections + ## + truststorePath: /opt/bitnami/zookeeper/config/certs/client/zookeeper.truststore.jks + ## @param tls.client.passwordsSecretName Existing secret containing Keystore and truststore passwords + ## + passwordsSecretName: "" + ## @param tls.client.passwordsSecretKeystoreKey The secret key from the tls.client.passwordsSecretName containing the password for the Keystore. + ## + passwordsSecretKeystoreKey: "" + ## @param tls.client.passwordsSecretTruststoreKey The secret key from the tls.client.passwordsSecretName containing the password for the Truststore. + ## + passwordsSecretTruststoreKey: "" + ## @param tls.client.keystorePassword Password to access KeyStore if needed + ## + keystorePassword: "" + ## @param tls.client.truststorePassword Password to access TrustStore if needed + ## + truststorePassword: "" + quorum: + ## @param tls.quorum.enabled Enable TLS for quorum protocol + ## + enabled: false + ## @param tls.quorum.auth SSL Quorum Client auth. Can be "none", "want" or "need". + ## + auth: "none" + ## @param tls.quorum.autoGenerated Create self-signed TLS certificates. Currently only supports PEM certificates. + ## + autoGenerated: false + ## @param tls.quorum.existingSecret Name of the existing secret containing the TLS certificates for ZooKeeper quorum protocol + ## + existingSecret: "" + ## @param tls.quorum.existingSecretKeystoreKey The secret key from the tls.quorum.existingSecret containing the Keystore. + ## + existingSecretKeystoreKey: "" + ## @param tls.quorum.existingSecretTruststoreKey The secret key from the tls.quorum.existingSecret containing the Truststore. + ## + existingSecretTruststoreKey: "" + ## @param tls.quorum.keystorePath Location of the KeyStore file used for Quorum protocol + ## + keystorePath: /opt/bitnami/zookeeper/config/certs/quorum/zookeeper.keystore.jks + ## @param tls.quorum.truststorePath Location of the TrustStore file used for Quorum protocol + ## + truststorePath: /opt/bitnami/zookeeper/config/certs/quorum/zookeeper.truststore.jks + ## @param tls.quorum.passwordsSecretName Existing secret containing Keystore and truststore passwords + ## + passwordsSecretName: "" + ## @param tls.quorum.passwordsSecretKeystoreKey The secret key from the tls.quorum.passwordsSecretName containing the password for the Keystore. + ## + passwordsSecretKeystoreKey: "" + ## @param tls.quorum.passwordsSecretTruststoreKey The secret key from the tls.quorum.passwordsSecretName containing the password for the Truststore. + ## + passwordsSecretTruststoreKey: "" + ## @param tls.quorum.keystorePassword Password to access KeyStore if needed + ## + keystorePassword: "" + ## @param tls.quorum.truststorePassword Password to access TrustStore if needed + ## + truststorePassword: "" + ## Init container resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## @param tls.resources.limits The resources limits for the TLS init container + ## @param tls.resources.requests The requested resources for the TLS init container + ## + resources: + limits: {} + requests: {} diff --git a/deployment/charts/kafka/templates/NOTES.txt b/deployment/charts/kafka/templates/NOTES.txt new file mode 100644 index 0000000..1bdfb33 --- /dev/null +++ b/deployment/charts/kafka/templates/NOTES.txt @@ -0,0 +1,310 @@ +CHART NAME: {{ .Chart.Name }} +CHART VERSION: {{ .Chart.Version }} +APP VERSION: {{ .Chart.AppVersion }} + +{{- 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/kafka/entrypoint.sh /opt/bitnami/scripts/kafka/run.sh + +{{- else }} + +{{- $replicaCount := int .Values.replicaCount -}} +{{- $releaseNamespace := .Release.Namespace -}} +{{- $clusterDomain := .Values.clusterDomain -}} +{{- $fullname := include "common.names.fullname" . -}} +{{- $clientProtocol := include "kafka.listenerType" (dict "protocol" .Values.auth.clientProtocol) -}} +{{- $externalClientProtocol := include "kafka.listenerType" (dict "protocol" (include "kafka.externalClientProtocol" . )) -}} +{{- $saslMechanisms := .Values.auth.sasl.mechanisms -}} +{{- $tlsEndpointIdentificationAlgorithm := default "" .Values.auth.tls.endpointIdentificationAlgorithm -}} +{{- $tlsPasswordSecret := printf "$(kubectl get secret %s --namespace %s -o jsonpath='{.data.password}' | base64 -d | cut -d , -f 1)" .Values.auth.tls.existingSecret $releaseNamespace -}} +{{- $tlsPassword := ternary .Values.auth.tls.password $tlsPasswordSecret (eq .Values.auth.tls.existingSecret "") -}} +{{- $servicePort := int .Values.service.ports.client -}} + +{{- if and (or (eq .Values.service.type "LoadBalancer") .Values.externalAccess.enabled) (eq $externalClientProtocol "PLAINTEXT") }} +--------------------------------------------------------------------------------------------- + WARNING + + By specifying "serviceType=LoadBalancer" and not configuring the authentication + you have most likely exposed the Kafka service externally without any + authentication mechanism. + + For security reasons, we strongly suggest that you switch to "ClusterIP" or + "NodePort". As alternative, you can also configure the Kafka authentication. + +--------------------------------------------------------------------------------------------- +{{- end }} + +** Please be patient while the chart is being deployed ** + +Kafka can be accessed by consumers via port {{ $servicePort }} on the following DNS name from within your cluster: + + {{ $fullname }}.{{ $releaseNamespace }}.svc.{{ $clusterDomain }} + +Each Kafka broker can be accessed by producers via port {{ $servicePort }} on the following DNS name(s) from within your cluster: + +{{- $brokerList := list }} +{{- range $e, $i := until $replicaCount }} +{{- $brokerList = append $brokerList (printf "%s-%d.%s-headless.%s.svc.%s:%d" $fullname $i $fullname $releaseNamespace $clusterDomain $servicePort) }} +{{- end }} +{{ join "\n" $brokerList | nindent 4 }} +{{- if (include "kafka.client.saslAuthentication" .) }} + +You need to configure your Kafka client to access using SASL authentication. To do so, you need to create the 'kafka_jaas.conf' and 'client.properties' configuration files with the content below: + + - kafka_jaas.conf: + +KafkaClient { +{{- if $saslMechanisms | regexFind "scram" }} +org.apache.kafka.common.security.scram.ScramLoginModule required +{{- else }} +org.apache.kafka.common.security.plain.PlainLoginModule required +{{- end }} +username="{{ index .Values.auth.sasl.jaas.clientUsers 0 }}" +password="$(kubectl get secret {{ $fullname }}-jaas --namespace {{ $releaseNamespace }} -o jsonpath='{.data.client-passwords}' | base64 -d | cut -d , -f 1)"; +}; + + - client.properties: + +security.protocol={{ $clientProtocol }} +{{- if $saslMechanisms | regexFind "scram-sha-256" }} +sasl.mechanism=SCRAM-SHA-256 +{{- else if $saslMechanisms | regexFind "scram-sha-512" }} +sasl.mechanism=SCRAM-SHA-512 +{{- else }} +sasl.mechanism=PLAIN +{{- end }} +{{- if eq $clientProtocol "SASL_SSL" }} +ssl.truststore.type={{ upper .Values.auth.tls.type }} + {{- if eq .Values.auth.tls.type "jks" }} +ssl.truststore.location=/tmp/kafka.truststore.jks + {{- if not (empty $tlsPassword) }} +ssl.truststore.password={{ $tlsPassword }} + {{- end }} + {{- else if eq .Values.auth.tls.type "pem" }} +ssl.truststore.certificates=-----BEGIN CERTIFICATE----- \ +... \ +-----END CERTIFICATE----- + {{- end }} + {{- if eq $tlsEndpointIdentificationAlgorithm "" }} +ssl.endpoint.identification.algorithm= + {{- end }} +{{- end }} + +{{- else if (include "kafka.client.tlsEncryption" .) }} + +You need to configure your Kafka client to access using TLS authentication. To do so, you need to create the 'client.properties' configuration file with the content below: + +security.protocol={{ $clientProtocol }} +ssl.truststore.type={{ upper .Values.auth.tls.type }} +{{- if eq .Values.auth.tls.type "jks" }} +ssl.truststore.location=/tmp/kafka.truststore.{{ .Values.auth.tls.type }} + {{- if not (empty $tlsPassword) }} +ssl.truststore.password={{ $tlsPassword }} + {{- end }} +{{- else if eq .Values.auth.tls.type "pem" }} +ssl.truststore.certificates=-----BEGIN CERTIFICATE----- \ +... \ +-----END CERTIFICATE----- +{{- end }} +{{- if eq .Values.auth.clientProtocol "mtls" }} +ssl.keystore.type={{ upper .Values.auth.tls.type }} + {{- if eq .Values.auth.tls.type "jks" }} +ssl.keystore.location=/tmp/client.keystore.jks + {{- if not (empty $tlsPassword) }} +ssl.keystore.password={{ $tlsPassword }} + {{- end }} + {{- else if eq .Values.auth.tls.type "pem" }} +ssl.keystore.certificate.chain=-----BEGIN CERTIFICATE----- \ +... \ +-----END CERTIFICATE----- +ssl.keystore.key=-----BEGIN ENCRYPTED PRIVATE KEY----- \ +... \ +-----END ENCRYPTED PRIVATE KEY----- + {{- end }} +{{- end }} +{{- if eq $tlsEndpointIdentificationAlgorithm "" }} +ssl.endpoint.identification.algorithm= +{{- end }} + +{{- end }} + +To create a pod that you can use as a Kafka client run the following commands: + + kubectl run {{ $fullname }}-client --restart='Never' --image {{ template "kafka.image" . }} --namespace {{ $releaseNamespace }} --command -- sleep infinity + {{- if or (include "kafka.client.saslAuthentication" .) (include "kafka.client.tlsEncryption" .) }} + kubectl cp --namespace {{ $releaseNamespace }} /path/to/client.properties {{ $fullname }}-client:/tmp/client.properties + {{- end }} + {{- if (include "kafka.client.saslAuthentication" .) }} + kubectl cp --namespace {{ $releaseNamespace }} /path/to/kafka_jaas.conf {{ $fullname }}-client:/tmp/kafka_jaas.conf + {{- end }} + {{- if and (include "kafka.client.tlsEncryption" .) (eq .Values.auth.tls.type "jks") }} + kubectl cp --namespace {{ $releaseNamespace }} ./kafka.truststore.jks {{ $fullname }}-client:/tmp/kafka.truststore.jks + {{- if eq .Values.auth.clientProtocol "mtls" }} + kubectl cp --namespace {{ $releaseNamespace }} ./client.keystore.jks {{ $fullname }}-client:/tmp/client.keystore.jks + {{- end }} + {{- end }} + kubectl exec --tty -i {{ $fullname }}-client --namespace {{ $releaseNamespace }} -- bash + {{- if (include "kafka.client.saslAuthentication" .) }} + export KAFKA_OPTS="-Djava.security.auth.login.config=/tmp/kafka_jaas.conf" + {{- end }} + + PRODUCER: + kafka-console-producer.sh \ + {{ if or (include "kafka.client.saslAuthentication" .) (include "kafka.client.tlsEncryption" .) }}--producer.config /tmp/client.properties \{{ end }} + --broker-list {{ join "," $brokerList }} \ + --topic test + + CONSUMER: + kafka-console-consumer.sh \ + {{ if or (include "kafka.client.saslAuthentication" .) (include "kafka.client.tlsEncryption" .) }}--consumer.config /tmp/client.properties \{{ end }} + --bootstrap-server {{ $fullname }}.{{ $releaseNamespace }}.svc.{{ $clusterDomain }}:{{ .Values.service.ports.client }} \ + --topic test \ + --from-beginning + +{{- if .Values.externalAccess.enabled }} + +To connect to your Kafka server from outside the cluster, follow the instructions below: + +{{- if eq "NodePort" .Values.externalAccess.service.type }} +{{- if .Values.externalAccess.service.domain }} + + Kafka brokers domain: Use your provided hostname to reach Kafka brokers, {{ .Values.externalAccess.service.domain }} + +{{- else }} + + Kafka brokers domain: You can get the external node IP from the Kafka configuration file with the following commands (Check the EXTERNAL listener) + + 1. Obtain the pod name: + + kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ template "kafka.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=kafka" + + 2. Obtain pod configuration: + + kubectl exec -it KAFKA_POD -- cat /opt/bitnami/kafka/config/server.properties | grep advertised.listeners + +{{- end }} + + Kafka brokers port: You will have a different node port for each Kafka broker. You can get the list of configured node ports using the command below: + + echo "$(kubectl get svc --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ template "kafka.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=kafka,pod" -o jsonpath='{.items[*].spec.ports[0].nodePort}' | tr ' ' '\n')" + +{{- else if contains "LoadBalancer" .Values.externalAccess.service.type }} + + NOTE: It may take a few minutes for the LoadBalancer IPs to be available. + Watch the status with: 'kubectl get svc --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ template "kafka.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=kafka,pod" -w' + + Kafka Brokers domain: You will have a different external IP for each Kafka broker. You can get the list of external IPs using the command below: + + echo "$(kubectl get svc --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ template "kafka.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=kafka,pod" -o jsonpath='{.items[*].status.loadBalancer.ingress[0].ip}' | tr ' ' '\n')" + + Kafka Brokers port: {{ .Values.externalAccess.service.ports.external }} + +{{- else if eq "ClusterIP" .Values.externalAccess.service.type }} + + Kafka brokers domain: Use your provided hostname to reach Kafka brokers, {{ .Values.externalAccess.service.domain }} + + Kafka brokers port: You will have a different port for each Kafka broker starting at {{ .Values.externalAccess.service.ports.external }} + +{{- end }} + +{{- if not (eq $clientProtocol $externalClientProtocol) }} +{{- if (include "kafka.client.saslAuthentication" .) }} + +You need to configure your Kafka client to access using SASL authentication. To do so, you need to create the 'kafka_jaas.conf' and 'client.properties' configuration files with the content below: + + - kafka_jaas.conf: + +KafkaClient { +{{- if $saslMechanisms | regexFind "scram" }} +org.apache.kafka.common.security.scram.ScramLoginModule required +{{- else }} +org.apache.kafka.common.security.plain.PlainLoginModule required +{{- end }} +username="{{ index .Values.auth.sasl.jaas.clientUsers 0 }}" +password="$(kubectl get secret {{ $fullname }}-jaas --namespace {{ $releaseNamespace }} -o jsonpath='{.data.client-passwords}' | base64 -d | cut -d , -f 1)"; +}; + + - client.properties: + +security.protocol={{ $externalClientProtocol }} +{{- if $saslMechanisms | regexFind "scram-sha-256" }} +sasl.mechanism=SCRAM-SHA-256 +{{- else if $saslMechanisms | regexFind "scram-sha-512" }} +sasl.mechanism=SCRAM-SHA-512 +{{- else }} +sasl.mechanism=PLAIN +{{- end }} +{{- if eq $externalClientProtocol "SASL_SSL" }} +ssl.truststore.type={{ upper .Values.auth.tls.type }} + {{- if eq .Values.auth.tls.type "jks" }} +ssl.truststore.location=/tmp/kafka.truststore.jks + {{- if not (empty $tlsPassword) }} +ssl.truststore.password={{ $tlsPassword }} + {{- end }} + {{- else if eq .Values.auth.tls.type "pem" }} +ssl.truststore.certificates=-----BEGIN CERTIFICATE----- \ +... \ +-----END CERTIFICATE----- + {{- end }} + {{- if eq $tlsEndpointIdentificationAlgorithm "" }} +ssl.endpoint.identification.algorithm= + {{- end }} +{{- end }} + +{{- else if (include "kafka.externalClient.tlsEncryption" .) }} + +You need to configure your Kafka client to access using TLS authentication. To do so, you need to create the 'client.properties' configuration file with the content below: + +security.protocol={{ $externalClientProtocol }} +ssl.truststore.type={{ upper .Values.auth.tls.type }} +{{- if eq .Values.auth.tls.type "jks" }} +ssl.truststore.location=/tmp/kafka.truststore.{{ .Values.auth.tls.type }} + {{- if not (empty $tlsPassword) }} +ssl.truststore.password={{ $tlsPassword }} + {{- end }} +{{- else if eq .Values.auth.tls.type "pem" }} +ssl.truststore.certificates=-----BEGIN CERTIFICATE----- \ +... \ +-----END CERTIFICATE----- +{{- end }} +{{- if eq .Values.auth.externalClientProtocol "mtls" }} +ssl.keystore.type={{ upper .Values.auth.tls.type }} + {{- if eq .Values.auth.tls.type "jks" }} +ssl.keystore.location=/tmp/client.keystore.jks + {{- if not (empty $tlsPassword) }} +ssl.keystore.password={{ $tlsPassword }} + {{- end }} + {{- else if eq .Values.auth.tls.type "pem" }} +ssl.keystore.certificate.chain=-----BEGIN CERTIFICATE----- \ +... \ +-----END CERTIFICATE----- +ssl.keystore.key=-----BEGIN ENCRYPTED PRIVATE KEY----- \ +... \ +-----END ENCRYPTED PRIVATE KEY----- + {{- end }} +{{- end }} +{{- if eq $tlsEndpointIdentificationAlgorithm "" }} +ssl.endpoint.identification.algorithm= +{{- end }} + +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +{{- include "kafka.checkRollingTags" . }} +{{- include "kafka.validateValues" . }} diff --git a/deployment/charts/kafka/templates/_helpers.tpl b/deployment/charts/kafka/templates/_helpers.tpl new file mode 100644 index 0000000..51ec867 --- /dev/null +++ b/deployment/charts/kafka/templates/_helpers.tpl @@ -0,0 +1,509 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Expand the name of the chart. +*/}} +{{- define "kafka.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified zookeeper name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "kafka.zookeeper.fullname" -}} +{{- if .Values.zookeeper.fullnameOverride -}} +{{- .Values.zookeeper.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default "zookeeper" .Values.zookeeper.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* + Create the name of the service account to use + */}} +{{- define "kafka.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "common.names.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Return the proper Kafka image name +*/}} +{{- define "kafka.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper image name (for the init container auto-discovery image) +*/}} +{{- define "kafka.externalAccess.autoDiscovery.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.externalAccess.autoDiscovery.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper image name (for the init container volume-permissions image) +*/}} +{{- define "kafka.volumePermissions.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.volumePermissions.image "global" .Values.global) }} +{{- end -}} + +{{/* +Create a default fully qualified Kafka exporter name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "kafka.metrics.kafka.fullname" -}} + {{- printf "%s-exporter" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }} +{{- end -}} + +{{/* + Create the name of the service account to use for Kafka exporter pods + */}} +{{- define "kafka.metrics.kafka.serviceAccountName" -}} +{{- if .Values.metrics.kafka.serviceAccount.create -}} + {{ default (include "kafka.metrics.kafka.fullname" .) .Values.metrics.kafka.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.metrics.kafka.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Return the proper Kafka exporter image name +*/}} +{{- define "kafka.metrics.kafka.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.metrics.kafka.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper JMX exporter image name +*/}} +{{- define "kafka.metrics.jmx.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.metrics.jmx.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names +*/}} +{{- define "kafka.imagePullSecrets" -}} +{{ include "common.images.pullSecrets" (dict "images" (list .Values.image .Values.externalAccess.autoDiscovery.image .Values.volumePermissions.image .Values.metrics.kafka.image .Values.metrics.jmx.image) "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper Storage Class +*/}} +{{- define "kafka.storageClass" -}} +{{/* +Helm 2.11 supports the assignment of a value to a variable defined in a different scope, +but Helm 2.9 and 2.10 does not support it, so we need to implement this if-else logic. +*/}} +{{- if .Values.global -}} + {{- if .Values.global.storageClass -}} + {{- if (eq "-" .Values.global.storageClass) -}} + {{- printf "storageClassName: \"\"" -}} + {{- else }} + {{- printf "storageClassName: %s" .Values.global.storageClass -}} + {{- end -}} + {{- else -}} + {{- if .Values.persistence.storageClass -}} + {{- if (eq "-" .Values.persistence.storageClass) -}} + {{- printf "storageClassName: \"\"" -}} + {{- else }} + {{- printf "storageClassName: %s" .Values.persistence.storageClass -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- else -}} + {{- if .Values.persistence.storageClass -}} + {{- if (eq "-" .Values.persistence.storageClass) -}} + {{- printf "storageClassName: \"\"" -}} + {{- else }} + {{- printf "storageClassName: %s" .Values.persistence.storageClass -}} + {{- end -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if authentication via SASL should be configured for client communications +*/}} +{{- define "kafka.client.saslAuthentication" -}} +{{- $saslProtocols := list "sasl" "sasl_tls" -}} +{{- if has .Values.auth.clientProtocol $saslProtocols -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if authentication via SASL should be configured for inter-broker communications +*/}} +{{- define "kafka.interBroker.saslAuthentication" -}} +{{- $saslProtocols := list "sasl" "sasl_tls" -}} +{{- if has .Values.auth.interBrokerProtocol $saslProtocols -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if encryption via TLS for client connections should be configured +*/}} +{{- define "kafka.client.tlsEncryption" -}} +{{- $tlsProtocols := list "tls" "mtls" "sasl_tls" -}} +{{- if (has .Values.auth.clientProtocol $tlsProtocols) -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return the configured value for the external client protocol, defaults to the same value as clientProtocol +*/}} +{{- define "kafka.externalClientProtocol" -}} + {{- coalesce .Values.auth.externalClientProtocol .Values.auth.clientProtocol -}} +{{- end -}} + +{{/* +Return true if encryption via TLS for external client connections should be configured +*/}} +{{- define "kafka.externalClient.tlsEncryption" -}} +{{- $tlsProtocols := list "tls" "mtls" "sasl_tls" -}} +{{- if (has (include "kafka.externalClientProtocol" . ) $tlsProtocols) -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if encryption via TLS for inter broker communication connections should be configured +*/}} +{{- define "kafka.interBroker.tlsEncryption" -}} +{{- $tlsProtocols := list "tls" "mtls" "sasl_tls" -}} +{{- if (has .Values.auth.interBrokerProtocol $tlsProtocols) -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if encryption via TLS should be configured +*/}} +{{- define "kafka.tlsEncryption" -}} +{{- if or (include "kafka.client.tlsEncryption" .) (include "kafka.interBroker.tlsEncryption" .) (include "kafka.externalClient.tlsEncryption" .) -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return the type of listener +Usage: +{{ include "kafka.listenerType" ( dict "protocol" .Values.path.to.the.Value ) }} +*/}} +{{- define "kafka.listenerType" -}} +{{- if eq .protocol "plaintext" -}} +PLAINTEXT +{{- else if or (eq .protocol "tls") (eq .protocol "mtls") -}} +SSL +{{- else if eq .protocol "sasl_tls" -}} +SASL_SSL +{{- else if eq .protocol "sasl" -}} +SASL_PLAINTEXT +{{- end -}} +{{- end -}} + +{{/* +Return the protocol used with zookeeper +*/}} +{{- define "kafka.zookeeper.protocol" -}} +{{- if and .Values.auth.zookeeper.tls.enabled .Values.zookeeper.auth.client.enabled .Values.auth.sasl.jaas.zookeeperUser -}} +SASL_SSL +{{- else if and .Values.auth.zookeeper.tls.enabled -}} +SSL +{{- else if and .Values.zookeeper.auth.client.enabled .Values.auth.sasl.jaas.zookeeperUser -}} +SASL +{{- else -}} +PLAINTEXT +{{- end -}} +{{- end -}} + +{{/* +Return the Kafka JAAS credentials secret +*/}} +{{- define "kafka.jaasSecretName" -}} +{{- $secretName := .Values.auth.sasl.jaas.existingSecret -}} +{{- if $secretName -}} + {{- printf "%s" (tpl $secretName $) -}} +{{- else -}} + {{- printf "%s-jaas" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a JAAS credentials secret object should be created +*/}} +{{- define "kafka.createJaasSecret" -}} +{{- $secretName := .Values.auth.sasl.jaas.existingSecret -}} +{{- if and (or (include "kafka.client.saslAuthentication" .) (include "kafka.interBroker.saslAuthentication" .) (and .Values.zookeeper.auth.client.enabled .Values.auth.sasl.jaas.zookeeperUser)) (empty $secretName) -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a TLS credentials secret object should be created +*/}} +{{- define "kafka.createTlsSecret" -}} +{{- if and (include "kafka.tlsEncryption" .) (empty .Values.auth.tls.existingSecrets) (eq .Values.auth.tls.type "pem") .Values.auth.tls.autoGenerated }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return the Kafka configuration configmap +*/}} +{{- define "kafka.configmapName" -}} +{{- if .Values.existingConfigmap -}} + {{- printf "%s" (tpl .Values.existingConfigmap $) -}} +{{- else -}} + {{- printf "%s-configuration" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + + +{{/* +Returns the secret name for the Kafka Provisioning client +*/}} +{{- define "kafka.client.passwordsSecretName" -}} +{{- if .Values.provisioning.auth.tls.passwordsSecret -}} + {{- printf "%s" (tpl .Values.provisioning.auth.tls.passwordsSecret $) -}} +{{- else -}} + {{- printf "%s-client-secret" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the service account to use for the Kafka Provisioning client +*/}} +{{- define "kafka.provisioning.serviceAccountName" -}} +{{- if .Values.provisioning.serviceAccount.create -}} + {{ default (include "common.names.fullname" .) .Values.provisioning.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.provisioning.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Return true if a configmap object should be created +*/}} +{{- define "kafka.createConfigmap" -}} +{{- if and .Values.config (not .Values.existingConfigmap) }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return the Kafka log4j ConfigMap name. +*/}} +{{- define "kafka.log4j.configMapName" -}} +{{- if .Values.existingLog4jConfigMap -}} + {{- printf "%s" (tpl .Values.existingLog4jConfigMap $) -}} +{{- else -}} + {{- printf "%s-log4j-configuration" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a log4j ConfigMap object should be created. +*/}} +{{- define "kafka.log4j.createConfigMap" -}} +{{- if and .Values.log4j (not .Values.existingLog4jConfigMap) }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return the SASL mechanism to use for the Kafka exporter to access Kafka +The exporter uses a different nomenclature so we need to do this hack +*/}} +{{- define "kafka.metrics.kafka.saslMechanism" -}} +{{- $saslMechanisms := .Values.auth.sasl.mechanisms }} +{{- if contains "scram-sha-512" $saslMechanisms }} + {{- print "scram-sha512" -}} +{{- else if contains "scram-sha-256" $saslMechanisms }} + {{- print "scram-sha256" -}} +{{- else -}} + {{- print "plain" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the Kafka configuration configmap +*/}} +{{- define "kafka.metrics.jmx.configmapName" -}} +{{- if .Values.metrics.jmx.existingConfigmap -}} + {{- printf "%s" (tpl .Values.metrics.jmx.existingConfigmap $) -}} +{{- else -}} + {{- printf "%s-jmx-configuration" (include "common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a configmap object should be created +*/}} +{{- define "kafka.metrics.jmx.createConfigmap" -}} +{{- if and .Values.metrics.jmx.enabled .Values.metrics.jmx.config (not .Values.metrics.jmx.existingConfigmap) }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Check if there are rolling tags in the images +*/}} +{{- define "kafka.checkRollingTags" -}} +{{- include "common.warnings.rollingTag" .Values.image }} +{{- include "common.warnings.rollingTag" .Values.externalAccess.autoDiscovery.image }} +{{- include "common.warnings.rollingTag" .Values.metrics.kafka.image }} +{{- include "common.warnings.rollingTag" .Values.metrics.jmx.image }} +{{- include "common.warnings.rollingTag" .Values.volumePermissions.image }} +{{- end -}} + +{{/* +Compile all warnings into a single message, and call fail. +*/}} +{{- define "kafka.validateValues" -}} +{{- $messages := list -}} +{{- $messages := append $messages (include "kafka.validateValues.authProtocols" .) -}} +{{- $messages := append $messages (include "kafka.validateValues.nodePortListLength" .) -}} +{{- $messages := append $messages (include "kafka.validateValues.domainSpecified" .) -}} +{{- $messages := append $messages (include "kafka.validateValues.externalAccessServiceType" .) -}} +{{- $messages := append $messages (include "kafka.validateValues.externalAccessAutoDiscoveryRBAC" .) -}} +{{- $messages := append $messages (include "kafka.validateValues.externalAccessAutoDiscoveryIPsOrNames" .) -}} +{{- $messages := append $messages (include "kafka.validateValues.externalAccessServiceList" (dict "element" "loadBalancerIPs" "context" .)) -}} +{{- $messages := append $messages (include "kafka.validateValues.externalAccessServiceList" (dict "element" "loadBalancerNames" "context" .)) -}} +{{- $messages := append $messages (include "kafka.validateValues.externalAccessServiceList" (dict "element" "loadBalancerAnnotations" "context" . )) -}} +{{- $messages := append $messages (include "kafka.validateValues.saslMechanisms" .) -}} +{{- $messages := append $messages (include "kafka.validateValues.tlsSecrets" .) -}} +{{- $messages := append $messages (include "kafka.validateValues.tlsSecrets.length" .) -}} +{{- $messages := append $messages (include "kafka.validateValues.tlsPasswords" .) -}} +{{- $messages := without $messages "" -}} +{{- $message := join "\n" $messages -}} + +{{- if $message -}} +{{- printf "\nVALUES VALIDATION:\n%s" $message | fail -}} +{{- end -}} +{{- end -}} + +{{/* Validate values of Kafka - Authentication protocols for Kafka */}} +{{- define "kafka.validateValues.authProtocols" -}} +{{- $authProtocols := list "plaintext" "tls" "mtls" "sasl" "sasl_tls" -}} +{{- if or (not (has .Values.auth.clientProtocol $authProtocols)) (not (has .Values.auth.interBrokerProtocol $authProtocols)) (not (has (include "kafka.externalClientProtocol" . ) $authProtocols)) -}} +kafka: auth.clientProtocol auth.externalClientProtocol auth.interBrokerProtocol + Available authentication protocols are "plaintext", "tls", "mtls", "sasl" and "sasl_tls" +{{- end -}} +{{- end -}} + +{{/* Validate values of Kafka - number of replicas must be the same as NodePort list */}} +{{- define "kafka.validateValues.nodePortListLength" -}} +{{- $replicaCount := int .Values.replicaCount }} +{{- $nodePortListLength := len .Values.externalAccess.service.nodePorts }} +{{- if and .Values.externalAccess.enabled (not .Values.externalAccess.autoDiscovery.enabled) (not (eq $replicaCount $nodePortListLength )) (eq .Values.externalAccess.service.type "NodePort") -}} +kafka: .Values.externalAccess.service.nodePorts + Number of replicas and nodePort array length must be the same. Currently: replicaCount = {{ $replicaCount }} and nodePorts = {{ $nodePortListLength }} +{{- end -}} +{{- end -}} + +{{/* Validate values of Kafka - domain must be defined if external service type ClusterIP */}} +{{- define "kafka.validateValues.domainSpecified" -}} +{{- if and (eq .Values.externalAccess.service.type "ClusterIP") (eq .Values.externalAccess.service.domain "") -}} +kafka: .Values.externalAccess.service.domain + Domain must be specified if service type ClusterIP is set for external service +{{- end -}} +{{- end -}} + +{{/* Validate values of Kafka - service type for external access */}} +{{- define "kafka.validateValues.externalAccessServiceType" -}} +{{- if and (not (eq .Values.externalAccess.service.type "NodePort")) (not (eq .Values.externalAccess.service.type "LoadBalancer")) (not (eq .Values.externalAccess.service.type "ClusterIP")) -}} +kafka: externalAccess.service.type + Available service type for external access are NodePort, LoadBalancer or ClusterIP. +{{- end -}} +{{- end -}} + +{{/* Validate values of Kafka - RBAC should be enabled when autoDiscovery is enabled */}} +{{- define "kafka.validateValues.externalAccessAutoDiscoveryRBAC" -}} +{{- if and .Values.externalAccess.enabled .Values.externalAccess.autoDiscovery.enabled (not .Values.rbac.create ) }} +kafka: rbac.create + By specifying "externalAccess.enabled=true" and "externalAccess.autoDiscovery.enabled=true" + an initContainer will be used to auto-detect the external IPs/ports by querying the + K8s API. Please note this initContainer requires specific RBAC resources. You can create them + by specifying "--set rbac.create=true". +{{- end -}} +{{- end -}} + +{{/* Validate values of Kafka - LoadBalancerIPs or LoadBalancerNames should be set when autoDiscovery is disabled */}} +{{- define "kafka.validateValues.externalAccessAutoDiscoveryIPsOrNames" -}} +{{- $loadBalancerNameListLength := len .Values.externalAccess.service.loadBalancerNames -}} +{{- $loadBalancerIPListLength := len .Values.externalAccess.service.loadBalancerIPs -}} +{{- if and .Values.externalAccess.enabled (eq .Values.externalAccess.service.type "LoadBalancer") (not .Values.externalAccess.autoDiscovery.enabled) (eq $loadBalancerNameListLength 0) (eq $loadBalancerIPListLength 0) }} +kafka: externalAccess.service.loadBalancerNames or externalAccess.service.loadBalancerIPs + By specifying "externalAccess.enabled=true", "externalAccess.autoDiscovery.enabled=false" and + "externalAccess.service.type=LoadBalancer" at least one of externalAccess.service.loadBalancerNames + or externalAccess.service.loadBalancerIPs must be set and the length of those arrays must be equal + to the number of replicas. +{{- end -}} +{{- end -}} + +{{/* Validate values of Kafka - number of replicas must be the same as loadBalancerIPs list */}} +{{- define "kafka.validateValues.externalAccessServiceList" -}} +{{- $replicaCount := int .context.Values.replicaCount }} +{{- $listLength := len (get .context.Values.externalAccess.service .element) -}} +{{- if and .context.Values.externalAccess.enabled (not .context.Values.externalAccess.autoDiscovery.enabled) (eq .context.Values.externalAccess.service.type "LoadBalancer") (gt $listLength 0) (not (eq $replicaCount $listLength)) }} +kafka: externalAccess.service.{{ .element }} + Number of replicas and {{ .element }} array length must be the same. Currently: replicaCount = {{ $replicaCount }} and {{ .element }} = {{ $listLength }} +{{- end -}} +{{- end -}} + +{{/* Validate values of Kafka - SASL mechanisms must be provided when using SASL */}} +{{- define "kafka.validateValues.saslMechanisms" -}} +{{- if and (or (.Values.auth.clientProtocol | regexFind "sasl") (.Values.auth.interBrokerProtocol | regexFind "sasl") (and .Values.zookeeper.auth.client.enabled .Values.auth.sasl.jaas.zookeeperUser)) (not .Values.auth.sasl.mechanisms) }} +kafka: auth.sasl.mechanisms + The SASL mechanisms are required when either auth.clientProtocol or auth.interBrokerProtocol use SASL or Zookeeper user is provided. +{{- end }} +{{- if not (contains .Values.auth.sasl.interBrokerMechanism .Values.auth.sasl.mechanisms) }} +kafka: auth.sasl.mechanisms + auth.sasl.interBrokerMechanism must be provided and it should be one of the specified mechanisms at auth.saslMechanisms +{{- end -}} +{{- end -}} + +{{/* Validate values of Kafka - Secrets containing TLS certs must be provided when TLS authentication is enabled */}} +{{- define "kafka.validateValues.tlsSecrets" -}} +{{- if and (include "kafka.tlsEncryption" .) (eq .Values.auth.tls.type "jks") (empty .Values.auth.tls.existingSecrets) }} +kafka: auth.tls.existingSecrets + A secret containing the Kafka JKS keystores and truststore is required + when TLS encryption in enabled and TLS format is "JKS" +{{- else if and (include "kafka.tlsEncryption" .) (eq .Values.auth.tls.type "pem") (empty .Values.auth.tls.existingSecrets) (not .Values.auth.tls.autoGenerated) }} +kafka: auth.tls.existingSecrets + A secret containing the Kafka TLS certificates and keys is required + when TLS encryption in enabled and TLS format is "PEM" +{{- end -}} +{{- end -}} + +{{/* Validate values of Kafka - The number of secrets containing TLS certs should be equal to the number of replicas */}} +{{- define "kafka.validateValues.tlsSecrets.length" -}} +{{- $replicaCount := int .Values.replicaCount }} +{{- if and (include "kafka.tlsEncryption" .) (not (empty .Values.auth.tls.existingSecrets)) }} +{{- $existingSecretsLength := len .Values.auth.tls.existingSecrets }} +{{- if ne $replicaCount $existingSecretsLength }} +kafka: .Values.auth.tls.existingSecrets + Number of replicas and existingSecrets array length must be the same. Currently: replicaCount = {{ $replicaCount }} and existingSecrets = {{ $existingSecretsLength }} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* Validate values of Kafka provisioning - keyPasswordSecretKey, keystorePasswordSecretKey or truststorePasswordSecretKey must not be used without passwordsSecret */}} +{{- define "kafka.validateValues.tlsPasswords" -}} +{{- if and (include "kafka.client.tlsEncryption" .) (not .Values.auth.tls.passwordsSecret) }} +{{- if or .Values.auth.tls.keyPasswordSecretKey .Values.auth.tls.keystorePasswordSecretKey .Values.auth.tls.truststorePasswordSecretKey }} +kafka: auth.tls.keyPasswordSecretKey,auth.tls.keystorePasswordSecretKey,auth.tls.truststorePasswordSecretKey + auth.tls.keyPasswordSecretKey,auth.tls.keystorePasswordSecretKey,auth.tls.truststorePasswordSecretKey + must not be used without passwordsSecret setted. +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/deployment/deployment/nginx-ingress-controller/templates/udp-configmap.yaml b/deployment/charts/kafka/templates/configmap.yaml similarity index 52% rename from deployment/deployment/nginx-ingress-controller/templates/udp-configmap.yaml rename to deployment/charts/kafka/templates/configmap.yaml index abb08b8..509fd1c 100644 --- a/deployment/deployment/nginx-ingress-controller/templates/udp-configmap.yaml +++ b/deployment/charts/kafka/templates/configmap.yaml @@ -1,16 +1,17 @@ -{{- if .Values.udp }} +{{- if (include "kafka.createConfigmap" .) }} apiVersion: v1 kind: ConfigMap metadata: - name: {{ printf "%s-udp" (include "common.names.fullname" .) }} + name: {{ printf "%s-configuration" (include "common.names.fullname" .) }} namespace: {{ .Release.Namespace | quote }} labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: controller {{- if .Values.commonLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- 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: {{- include "common.tplvalues.render" (dict "value" .Values.udp "context" $) | nindent 2 }} -{{- end }} +data: + server.properties: |- + {{ .Values.config | nindent 4 }} +{{- end -}} diff --git a/deployment/deployment/nginx-ingress-controller/templates/extra-list.yaml b/deployment/charts/kafka/templates/extra-list.yaml similarity index 100% rename from deployment/deployment/nginx-ingress-controller/templates/extra-list.yaml rename to deployment/charts/kafka/templates/extra-list.yaml diff --git a/deployment/charts/kafka/templates/jaas-secret.yaml b/deployment/charts/kafka/templates/jaas-secret.yaml new file mode 100644 index 0000000..8f632e5 --- /dev/null +++ b/deployment/charts/kafka/templates/jaas-secret.yaml @@ -0,0 +1,40 @@ +{{- if (include "kafka.createJaasSecret" .) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ printf "%s-jaas" (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 (include "kafka.client.saslAuthentication" .) }} + {{- $clientUsers := .Values.auth.sasl.jaas.clientUsers }} + {{- $clientPasswords := .Values.auth.sasl.jaas.clientPasswords }} + {{- if $clientPasswords }} + client-passwords: {{ join "," $clientPasswords | b64enc | quote }} + system-user-password: {{ index $clientPasswords 0 | b64enc | quote }} + {{- else }} + {{- $passwords := list }} + {{- range $clientUsers }} + {{- $passwords = append $passwords (randAlphaNum 10) }} + {{- end }} + client-passwords: {{ join "," $passwords | b64enc | quote }} + system-user-password: {{ index $passwords 0 | b64enc | quote }} + {{- end }} + {{- end }} + {{- $zookeeperUser := .Values.auth.sasl.jaas.zookeeperUser }} + {{- if and .Values.zookeeper.auth.client.enabled $zookeeperUser }} + {{- $zookeeperPassword := .Values.auth.sasl.jaas.zookeeperPassword }} + zookeeper-password: {{ default (randAlphaNum 10) $zookeeperPassword | b64enc | quote }} + {{- end }} + {{- if (include "kafka.interBroker.saslAuthentication" .) }} + {{- $interBrokerPassword := .Values.auth.sasl.jaas.interBrokerPassword }} + inter-broker-password: {{ default (randAlphaNum 10) $interBrokerPassword | b64enc | quote }} + {{- end }} +{{- end }} diff --git a/deployment/charts/kafka/templates/jmx-configmap.yaml b/deployment/charts/kafka/templates/jmx-configmap.yaml new file mode 100644 index 0000000..9207f6d --- /dev/null +++ b/deployment/charts/kafka/templates/jmx-configmap.yaml @@ -0,0 +1,64 @@ +{{- if (include "kafka.metrics.jmx.createConfigmap" .) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-jmx-configuration" (include "common.names.fullname" .) }} + namespace: {{ .Release.Namespace | quote }} + 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.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: + jmx-kafka-prometheus.yml: |- + {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.jmx.config "context" $ ) | nindent 4 }} + rules: + - pattern: kafka.controller<>(Value) + name: kafka_controller_$1_$2_$4 + labels: + broker_id: "$3" + - pattern: kafka.controller<>(Value) + name: kafka_controller_$1_$2_$3 + - pattern: kafka.controller<>(Value) + name: kafka_controller_$1_$2_$3 + - pattern: kafka.controller<>(Count) + name: kafka_controller_$1_$2_$3 + - pattern: kafka.server<>(Value) + name: kafka_server_$1_$2_$4 + labels: + client_id: "$3" + - pattern : kafka.network<>(Value) + name: kafka_network_$1_$2_$4 + labels: + network_processor: $3 + - pattern : kafka.network<>(Count) + name: kafka_network_$1_$2_$4 + labels: + request: $3 + - pattern: kafka.server<>(Count|OneMinuteRate) + name: kafka_server_$1_$2_$4 + labels: + topic: $3 + - pattern: kafka.server<>(Value) + name: kafka_server_$1_$2_$3_$4 + - pattern: kafka.server<>(Count|Value|OneMinuteRate) + name: kafka_server_$1_total_$2_$3 + - pattern: kafka.server<>(queue-size) + name: kafka_server_$1_$2 + - pattern: java.lang<(.+)>(\w+) + name: java_lang_$1_$4_$3_$2 + - pattern: java.lang<>(\w+) + name: java_lang_$1_$3_$2 + - pattern : java.lang + - pattern: kafka.log<>Value + name: kafka_log_$1_$2 + labels: + topic: $3 + partition: $4 + {{- if .Values.metrics.jmx.extraRules }} + {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.jmx.extraRules "context" $ ) | nindent 6 }} + {{- end }} +{{- end -}} diff --git a/deployment/charts/kafka/templates/jmx-metrics-svc.yaml b/deployment/charts/kafka/templates/jmx-metrics-svc.yaml new file mode 100644 index 0000000..35c79f4 --- /dev/null +++ b/deployment/charts/kafka/templates/jmx-metrics-svc.yaml @@ -0,0 +1,34 @@ +{{- if .Values.metrics.jmx.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ printf "%s-jmx-metrics" (include "common.names.fullname" .) }} + namespace: {{ .Release.Namespace | quote }} + 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 or .Values.metrics.jmx.service.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.metrics.jmx.service.annotations }} + {{ include "common.tplvalues.render" ( dict "value" .Values.metrics.jmx.service.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: ClusterIP + sessionAffinity: {{ .Values.metrics.jmx.service.sessionAffinity }} + {{- if .Values.metrics.jmx.service.clusterIP }} + clusterIP: {{ .Values.metrics.jmx.service.clusterIP }} + {{- end }} + ports: + - name: http-metrics + port: {{ .Values.metrics.jmx.service.ports.metrics }} + protocol: TCP + targetPort: metrics + selector: {{- include "common.labels.matchLabels" . | nindent 4 }} + app.kubernetes.io/component: kafka +{{- end }} diff --git a/deployment/charts/kafka/templates/kafka-metrics-deployment.yaml b/deployment/charts/kafka/templates/kafka-metrics-deployment.yaml new file mode 100644 index 0000000..bf731f2 --- /dev/null +++ b/deployment/charts/kafka/templates/kafka-metrics-deployment.yaml @@ -0,0 +1,171 @@ +{{- if .Values.metrics.kafka.enabled }} +{{- $replicaCount := int .Values.replicaCount -}} +{{- $releaseNamespace := .Release.Namespace -}} +{{- $clusterDomain := .Values.clusterDomain -}} +{{- $fullname := include "common.names.fullname" . -}} +{{- $servicePort := int .Values.service.ports.client -}} +apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} +kind: Deployment +metadata: + name: {{ include "kafka.metrics.kafka.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: cluster-metrics + {{- 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 + selector: + matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: cluster-metrics + template: + metadata: + labels: {{- include "common.labels.standard" . | nindent 8 }} + app.kubernetes.io/component: cluster-metrics + {{- if .Values.metrics.kafka.podLabels }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.kafka.podLabels "context" $) | nindent 8 }} + {{- end }} + annotations: + {{- if .Values.metrics.kafka.podAnnotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.kafka.podAnnotations "context" $) | nindent 8 }} + {{- end }} + spec: + {{- include "kafka.imagePullSecrets" . | nindent 6 }} + {{- if .Values.metrics.kafka.hostAliases }} + hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.kafka.hostAliases "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.metrics.kafka.affinity }} + affinity: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.kafka.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.metrics.kafka.podAffinityPreset "component" "metrics" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.metrics.kafka.podAntiAffinityPreset "component" "metrics" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.metrics.kafka.nodeAffinityPreset.type "key" .Values.metrics.kafka.nodeAffinityPreset.key "values" .Values.metrics.kafka.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.metrics.kafka.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.kafka.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.metrics.kafka.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.kafka.tolerations "context" .) | nindent 8 }} + {{- end }} + {{- if .Values.metrics.kafka.topologySpreadConstraints }} + topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.kafka.topologySpreadConstraints "context" .) | nindent 8 }} + {{- end }} + {{- if .Values.metrics.kafka.priorityClassName }} + priorityClassName: {{ .Values.metrics.kafka.priorityClassName }} + {{- end }} + {{- if .Values.metrics.kafka.schedulerName }} + schedulerName: {{ .Values.metrics.kafka.schedulerName }} + {{- end }} + {{- if .Values.metrics.kafka.podSecurityContext.enabled }} + securityContext: {{- omit .Values.metrics.kafka.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + serviceAccountName: {{ template "kafka.metrics.kafka.serviceAccountName" . }} + {{- if .Values.metrics.kafka.initContainers }} + initContainers: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.kafka.initContainers "context" $) | nindent 8 }} + {{- end }} + containers: + - name: kafka-exporter + image: {{ include "kafka.metrics.kafka.image" . }} + imagePullPolicy: {{ .Values.metrics.kafka.image.pullPolicy | quote }} + {{- if .Values.metrics.kafka.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.metrics.kafka.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.metrics.kafka.command }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.kafka.command "context" $) | nindent 12 }} + {{- else }} + command: + - bash + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} + {{- else if .Values.metrics.kafka.args }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.kafka.args "context" $) | nindent 12 }} + {{- else }} + args: + - -ce + - | + kafka_exporter \ + {{- range $i, $e := until $replicaCount }} + --kafka.server={{ $fullname }}-{{ $i }}.{{ $fullname }}-headless.{{ $releaseNamespace }}.svc.{{ $clusterDomain }}:{{ $servicePort }} \ + {{- end }} + {{- if (include "kafka.client.saslAuthentication" .) }} + --sasl.enabled \ + --sasl.username=$SASL_USERNAME \ + --sasl.password=$SASL_USER_PASSWORD \ + --sasl.mechanism={{ include "kafka.metrics.kafka.saslMechanism" . }} \ + {{- end }} + {{- if (include "kafka.client.tlsEncryption" .) }} + --tls.enabled \ + {{- if .Values.metrics.kafka.certificatesSecret }} + --tls.key-file=/opt/bitnami/kafka-exporter/certs/{{ .Values.metrics.kafka.tlsKey }} \ + --tls.cert-file=/opt/bitnami/kafka-exporter/certs/{{ .Values.metrics.kafka.tlsCert }} \ + {{- if .Values.metrics.kafka.tlsCaSecret }} + --tls.ca-file=/opt/bitnami/kafka-exporter/cacert/{{ .Values.metrics.kafka.tlsCaCert }} \ + {{- else }} + --tls.ca-file=/opt/bitnami/kafka-exporter/certs/{{ .Values.metrics.kafka.tlsCaCert }} \ + {{- end }} + {{- end }} + {{- end }} + {{- range $key, $value := .Values.metrics.kafka.extraFlags }} + --{{ $key }}{{ if $value }}={{ $value }}{{ end }} \ + {{- end }} + --web.listen-address=:{{ .Values.metrics.kafka.containerPorts.metrics }} + {{- end }} + {{- if (include "kafka.client.saslAuthentication" .) }} + {{- $clientUsers := .Values.auth.sasl.jaas.clientUsers }} + env: + - name: SASL_USERNAME + value: {{ index $clientUsers 0 | quote }} + - name: SASL_USER_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "kafka.jaasSecretName" . }} + key: system-user-password + {{- end }} + ports: + - name: metrics + containerPort: {{ .Values.metrics.kafka.containerPorts.metrics }} + {{- if .Values.metrics.kafka.resources }} + resources: {{ toYaml .Values.metrics.kafka.resources | nindent 12 }} + {{- end }} + volumeMounts: + {{- if .Values.metrics.kafka.extraVolumeMounts }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.kafka.extraVolumeMounts "context" $) | nindent 12 }} + {{- end }} + {{- if and (include "kafka.client.tlsEncryption" .) .Values.metrics.kafka.certificatesSecret }} + - name: kafka-exporter-certificates + mountPath: /opt/bitnami/kafka-exporter/certs/ + readOnly: true + {{- if .Values.metrics.kafka.tlsCaSecret }} + - name: kafka-exporter-ca-certificate + mountPath: /opt/bitnami/kafka-exporter/cacert/ + readOnly: true + {{- end }} + {{- end }} + {{- if .Values.metrics.kafka.sidecars }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.kafka.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + {{- if .Values.metrics.kafka.extraVolumes }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.kafka.extraVolumes "context" $) | nindent 8 }} + {{- end }} + {{- if and (include "kafka.client.tlsEncryption" .) .Values.metrics.kafka.certificatesSecret }} + - name: kafka-exporter-certificates + secret: + secretName: {{ .Values.metrics.kafka.certificatesSecret }} + defaultMode: 0440 + {{- if .Values.metrics.kafka.tlsCaSecret }} + - name: kafka-exporter-ca-certificate + secret: + secretName: {{ .Values.metrics.kafka.tlsCaSecret }} + defaultMode: 0440 + {{- end }} + {{- end }} +{{- end }} diff --git a/deployment/charts/kafka/templates/kafka-metrics-serviceaccount.yaml b/deployment/charts/kafka/templates/kafka-metrics-serviceaccount.yaml new file mode 100644 index 0000000..f8e3eb3 --- /dev/null +++ b/deployment/charts/kafka/templates/kafka-metrics-serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.metrics.kafka.enabled .Values.metrics.kafka.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "kafka.metrics.kafka.serviceAccountName" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: cluster-metrics + {{- 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 }} +automountServiceAccountToken: {{ .Values.metrics.kafka.serviceAccount.automountServiceAccountToken }} +{{- end }} diff --git a/deployment/charts/kafka/templates/kafka-metrics-svc.yaml b/deployment/charts/kafka/templates/kafka-metrics-svc.yaml new file mode 100644 index 0000000..9daae4a --- /dev/null +++ b/deployment/charts/kafka/templates/kafka-metrics-svc.yaml @@ -0,0 +1,34 @@ +{{- if .Values.metrics.kafka.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ printf "%s-metrics" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: cluster-metrics + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if or .Values.metrics.kafka.service.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.metrics.kafka.service.annotations }} + {{ include "common.tplvalues.render" ( dict "value" .Values.metrics.kafka.service.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: ClusterIP + sessionAffinity: {{ .Values.metrics.kafka.service.sessionAffinity }} + {{- if .Values.metrics.kafka.service.clusterIP }} + clusterIP: {{ .Values.metrics.kafka.service.clusterIP }} + {{- end }} + ports: + - name: http-metrics + port: {{ .Values.metrics.kafka.service.ports.metrics }} + protocol: TCP + targetPort: metrics + selector: {{- include "common.labels.matchLabels" . | nindent 4 }} + app.kubernetes.io/component: cluster-metrics +{{- end }} diff --git a/deployment/charts/kafka/templates/kafka-provisioning-secret.yaml b/deployment/charts/kafka/templates/kafka-provisioning-secret.yaml new file mode 100644 index 0000000..0c0fb1b --- /dev/null +++ b/deployment/charts/kafka/templates/kafka-provisioning-secret.yaml @@ -0,0 +1,19 @@ +{{- if and .Values.provisioning.enabled (include "kafka.client.tlsEncryption" .) (not .Values.provisioning.auth.tls.passwordsSecret) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "kafka.client.passwordsSecretName" . }} + 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: + truststore-password: {{ default "" .Values.provisioning.auth.tls.keystorePassword | b64enc | quote }} + keystore-password: {{ default "" .Values.provisioning.auth.tls.truststorePassword | b64enc | quote }} + key-password: {{ default "" .Values.provisioning.auth.tls.keyPassword | b64enc | quote }} +{{- end }} diff --git a/deployment/charts/kafka/templates/kafka-provisioning-serviceaccount.yaml b/deployment/charts/kafka/templates/kafka-provisioning-serviceaccount.yaml new file mode 100644 index 0000000..4761467 --- /dev/null +++ b/deployment/charts/kafka/templates/kafka-provisioning-serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.provisioning.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "kafka.provisioning.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 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.provisioning.serviceAccount.automountServiceAccountToken }} +{{- end }} diff --git a/deployment/charts/kafka/templates/kafka-provisioning.yaml b/deployment/charts/kafka/templates/kafka-provisioning.yaml new file mode 100644 index 0000000..765e883 --- /dev/null +++ b/deployment/charts/kafka/templates/kafka-provisioning.yaml @@ -0,0 +1,260 @@ +{{- if .Values.provisioning.enabled }} +{{- $replicaCount := int .Values.replicaCount }} +kind: Job +apiVersion: batch/v1 +metadata: + name: {{ printf "%s-provisioning" (include "common.names.fullname" .) }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: kafka-provisioning + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + annotations: + helm.sh/hook: post-install,post-upgrade + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + template: + metadata: + labels: {{- include "common.labels.standard" . | nindent 8 }} + app.kubernetes.io/component: kafka-provisioning + {{- if .Values.provisioning.podLabels }} + {{- include "common.tplvalues.render" (dict "value" .Values.provisioning.podLabels "context" $) | nindent 8 }} + {{- end }} + annotations: + {{- if .Values.provisioning.podAnnotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.provisioning.podAnnotations "context" $) | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ template "kafka.provisioning.serviceAccountName" . }} + {{- include "kafka.imagePullSecrets" . | nindent 6 }} + {{- if .Values.provisioning.schedulerName }} + schedulerName: {{ .Values.provisioning.schedulerName | quote }} + {{- end }} + {{- if .Values.provisioning.podSecurityContext.enabled }} + securityContext: {{- omit .Values.provisioning.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + restartPolicy: OnFailure + terminationGracePeriodSeconds: 0 + {{- if .Values.provisioning.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" ( dict "value" .Values.provisioning.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.provisioning.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.provisioning.tolerations "context" .) | nindent 8 }} + {{- end }} + {{- if or .Values.provisioning.initContainers .Values.provisioning.waitForKafka }} + initContainers: + {{- if .Values.provisioning.waitForKafka }} + - name: wait-for-available-kafka + image: {{ include "kafka.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy | quote }} + {{- if .Values.provisioning.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.provisioning.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + command: + - /bin/bash + args: + - -ec + - | + wait-for-port \ + --host={{ include "common.names.fullname" . }} \ + --state=inuse \ + --timeout=120 \ + {{ .Values.service.ports.client | int64 }}; + echo "Kafka is available"; + {{- if .Values.provisioning.resources }} + resources: {{- toYaml .Values.provisioning.resources | nindent 12 }} + {{- end }} + {{- end }} + {{- if .Values.provisioning.initContainers }} + {{- include "common.tplvalues.render" ( dict "value" .Values.provisioning.initContainers "context" $ ) | nindent 8 }} + {{- end }} + {{- end }} + containers: + - name: kafka-provisioning + image: {{ include "kafka.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy | quote }} + {{- if .Values.provisioning.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.provisioning.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.provisioning.command }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.provisioning.command "context" $) | nindent 12 }} + {{- else }} + command: + - /bin/bash + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} + {{- else if .Values.provisioning.args }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.provisioning.args "context" $) | nindent 12 }} + {{- else }} + args: + - -ec + - | + echo "Configuring environment" + . /opt/bitnami/scripts/libkafka.sh + export CLIENT_CONF="${CLIENT_CONF:-/opt/bitnami/kafka/config/client.properties}" + if [ ! -f "$CLIENT_CONF" ]; then + touch $CLIENT_CONF + + kafka_common_conf_set "$CLIENT_CONF" security.protocol {{ include "kafka.listenerType" ( dict "protocol" .Values.auth.clientProtocol ) | quote }} + {{- if (include "kafka.client.tlsEncryption" .) }} + kafka_common_conf_set "$CLIENT_CONF" ssl.keystore.type {{ upper .Values.provisioning.auth.tls.type | quote }} + kafka_common_conf_set "$CLIENT_CONF" ssl.truststore.type {{ upper .Values.provisioning.auth.tls.type | quote }} + ! is_empty_value "$KAFKA_CLIENT_KEY_PASSWORD" && kafka_common_conf_set "$CLIENT_CONF" ssl.key.password "$KAFKA_CLIENT_KEY_PASSWORD" + {{- if eq (upper .Values.provisioning.auth.tls.type) "PEM" }} + file_to_multiline_property() { + awk 'NR > 1{print line" \\"}{line=$0;}END{print $0" "}' <"${1:?missing file}" + } + kafka_common_conf_set "$CLIENT_CONF" ssl.keystore.key "$(file_to_multiline_property "/certs/{{ .Values.provisioning.auth.tls.key }}")" + kafka_common_conf_set "$CLIENT_CONF" ssl.keystore.certificate.chain "$(file_to_multiline_property "/certs/{{ .Values.provisioning.auth.tls.caCert }}")" + kafka_common_conf_set "$CLIENT_CONF" ssl.truststore.certificates "$(file_to_multiline_property "/certs/{{ .Values.provisioning.auth.tls.cert }}")" + {{- else if eq (upper .Values.provisioning.auth.tls.type) "JKS" }} + kafka_common_conf_set "$CLIENT_CONF" ssl.keystore.location "/certs/{{ .Values.provisioning.auth.tls.keystore }}" + kafka_common_conf_set "$CLIENT_CONF" ssl.truststore.location "/certs/{{ .Values.provisioning.auth.tls.truststore }}" + ! is_empty_value "$KAFKA_CLIENT_KEYSTORE_PASSWORD" && kafka_common_conf_set "$CLIENT_CONF" ssl.keystore.password "$KAFKA_CLIENT_KEYSTORE_PASSWORD" + ! is_empty_value "$KAFKA_CLIENT_TRUSTSTORE_PASSWORD" && kafka_common_conf_set "$CLIENT_CONF" ssl.truststore.password "$KAFKA_CLIENT_TRUSTSTORE_PASSWORD" + {{- end }} + {{- end }} + {{- if (include "kafka.client.saslAuthentication" .) }} + {{- if contains "plain" .Values.auth.sasl.mechanisms }} + kafka_common_conf_set "$CLIENT_CONF" sasl.mechanism PLAIN + kafka_common_conf_set "$CLIENT_CONF" sasl.jaas.config "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"$SASL_USERNAME\" password=\"$SASL_USER_PASSWORD\";" + {{- else if contains "scram-sha-256" .Values.auth.sasl.mechanisms }} + kafka_common_conf_set "$CLIENT_CONF" sasl.mechanism SCRAM-SHA-256 + kafka_common_conf_set "$CLIENT_CONF" sasl.jaas.config "org.apache.kafka.common.security.scram.ScramLoginModule required username=\"$SASL_USERNAME\" password=\"$SASL_USER_PASSWORD\";" + {{- else if contains "scram-sha-512" .Values.auth.sasl.mechanisms }} + kafka_common_conf_set "$CLIENT_CONF" sasl.mechanism SCRAM-SHA-512 + kafka_common_conf_set "$CLIENT_CONF" sasl.jaas.config "org.apache.kafka.common.security.scram.ScramLoginModule required username=\"$SASL_USERNAME\" password=\"$SASL_USER_PASSWORD\";" + {{- end }} + {{- end }} + fi + + echo "Running pre-provisioning script if any given" + {{ .Values.provisioning.preScript | nindent 14 }} + + kafka_provisioning_commands=( + {{- range $topic := .Values.provisioning.topics }} + "/opt/bitnami/kafka/bin/kafka-topics.sh \ + --create \ + --if-not-exists \ + --bootstrap-server ${KAFKA_SERVICE} \ + --replication-factor {{ $topic.replicationFactor | default $.Values.provisioning.replicationFactor }} \ + --partitions {{ $topic.partitions | default $.Values.provisioning.numPartitions }} \ + {{- range $name, $value := $topic.config }} + --config {{ $name }}={{ $value }} \ + {{- end }} + --command-config ${CLIENT_CONF} \ + --topic {{ $topic.name }}" + {{- end }} + {{- range $command := .Values.provisioning.extraProvisioningCommands }} + {{- $command | quote | nindent 16 }} + {{- end }} + ) + + echo "Starting provisioning" + for ((index=0; index < ${#kafka_provisioning_commands[@]}; index+={{ .Values.provisioning.parallel }})) + do + for j in $(seq ${index} $((${index}+{{ .Values.provisioning.parallel }}-1))) + do + ${kafka_provisioning_commands[j]} & # Async command + done + wait # Wait the end of the jobs + done + + echo "Running post-provisioning script if any given" + {{ .Values.provisioning.postScript | nindent 14 }} + + echo "Provisioning succeeded" + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" (or .Values.image.debug .Values.diagnosticMode.enabled) | quote }} + {{- if (include "kafka.client.tlsEncryption" .) }} + - name: KAFKA_CLIENT_KEY_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "kafka.client.passwordsSecretName" . }} + key: {{ .Values.provisioning.auth.tls.keyPasswordSecretKey }} + - name: KAFKA_CLIENT_KEYSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "kafka.client.passwordsSecretName" . }} + key: {{ .Values.provisioning.auth.tls.keystorePasswordSecretKey }} + - name: KAFKA_CLIENT_TRUSTSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "kafka.client.passwordsSecretName" . }} + key: {{ .Values.provisioning.auth.tls.truststorePasswordSecretKey }} + {{- end }} + - name: KAFKA_SERVICE + value: {{ printf "%s:%d" (include "common.names.fullname" .) (.Values.service.ports.client | int64) }} + {{- if (include "kafka.client.saslAuthentication" .) }} + {{- $clientUsers := .Values.auth.sasl.jaas.clientUsers }} + - name: SASL_USERNAME + value: {{ index $clientUsers 0 | quote }} + - name: SASL_USER_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "kafka.jaasSecretName" . }} + key: system-user-password + {{- end }} + {{- if .Values.provisioning.extraEnvVars }} + {{- include "common.tplvalues.render" ( dict "value" .Values.provisioning.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + {{- if or .Values.provisioning.extraEnvVarsCM .Values.provisioning.extraEnvVarsSecret }} + envFrom: + {{- if .Values.provisioning.extraEnvVarsCM }} + - configMapRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.provisioning.extraEnvVarsCM "context" $) }} + {{- end }} + {{- if .Values.provisioning.extraEnvVarsSecret }} + - secretRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.provisioning.extraEnvVarsSecret "context" $) }} + {{- end }} + {{- end }} + {{- if .Values.provisioning.resources }} + resources: {{- toYaml .Values.provisioning.resources | nindent 12 }} + {{- end }} + volumeMounts: + {{- if or .Values.log4j .Values.existingLog4jConfigMap }} + - name: log4j-config + mountPath: {{ .Values.persistence.mountPath }}/config/log4j.properties + subPath: log4j.properties + {{- end }} + {{- if (include "kafka.client.tlsEncryption" .) }} + {{- if not (empty .Values.provisioning.auth.tls.certificatesSecret) }} + - name: kafka-client-certs + mountPath: /certs + readOnly: true + {{- end }} + {{- end }} + {{- if .Values.provisioning.extraVolumeMounts }} + {{- include "common.tplvalues.render" (dict "value" .Values.provisioning.extraVolumeMounts "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.provisioning.sidecars }} + {{- include "common.tplvalues.render" (dict "value" .Values.provisioning.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + {{- if or .Values.log4j .Values.existingLog4jConfigMap }} + - name: log4j-config + configMap: + name: {{ include "kafka.log4j.configMapName" . }} + {{ end }} + {{- if (include "kafka.client.tlsEncryption" .) }} + {{- if not (empty .Values.provisioning.auth.tls.certificatesSecret) }} + - name: kafka-client-certs + secret: + secretName: {{ .Values.provisioning.auth.tls.certificatesSecret }} + defaultMode: 256 + {{- end }} + {{- end }} + {{- if .Values.provisioning.extraVolumes }} + {{- include "common.tplvalues.render" (dict "value" .Values.provisioning.extraVolumes "context" $) | nindent 8 }} + {{- end }} +{{- end }} diff --git a/deployment/charts/kafka/templates/log4j-configmap.yaml b/deployment/charts/kafka/templates/log4j-configmap.yaml new file mode 100644 index 0000000..8f7bc6c --- /dev/null +++ b/deployment/charts/kafka/templates/log4j-configmap.yaml @@ -0,0 +1,17 @@ +{{- if (include "kafka.log4j.createConfigMap" .) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "kafka.log4j.configMapName" . }} + 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 }} +data: + log4j.properties: |- + {{- include "common.tplvalues.render" ( dict "value" .Values.log4j "context" $ ) | nindent 4 }} +{{- end -}} diff --git a/deployment/charts/kafka/templates/networkpolicy-egress.yaml b/deployment/charts/kafka/templates/networkpolicy-egress.yaml new file mode 100644 index 0000000..068024a --- /dev/null +++ b/deployment/charts/kafka/templates/networkpolicy-egress.yaml @@ -0,0 +1,22 @@ +{{- if and .Values.networkPolicy.enabled .Values.networkPolicy.egressRules.customRules }} +kind: NetworkPolicy +apiVersion: {{ include "common.capabilities.networkPolicy.apiVersion" . }} +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.matchLabels" . | nindent 6 }} + policyTypes: + - Egress + egress: + {{- include "common.tplvalues.render" (dict "value" .Values.networkPolicy.egressRules.customRules "context" $) | nindent 4 }} +{{- end }} diff --git a/deployment/charts/kafka/templates/networkpolicy-ingress.yaml b/deployment/charts/kafka/templates/networkpolicy-ingress.yaml new file mode 100644 index 0000000..258dcab --- /dev/null +++ b/deployment/charts/kafka/templates/networkpolicy-ingress.yaml @@ -0,0 +1,53 @@ +{{- if .Values.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: {{ include "common.capabilities.networkPolicy.apiVersion" . }} +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: + {{- include "common.labels.matchLabels" . | nindent 6 }} + policyTypes: + - Ingress + ingress: + # Allow client connections + - ports: + - port: {{ .Values.containerPorts.client }} + {{- if not .Values.networkPolicy.allowExternal }} + from: + - podSelector: + matchLabels: + {{ template "common.names.fullname" . }}-client: "true" + {{- if .Values.networkPolicy.explicitNamespacesSelector }} + namespaceSelector: {{- toYaml .Values.networkPolicy.explicitNamespacesSelector | nindent 12 }} + {{- end }} + {{- end }} + # Allow communication inter-broker + - ports: + - port: {{ .Values.containerPorts.internal }} + from: + - podSelector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 14 }} + # Allow External connection + {{- if .Values.externalAccess.enabled }} + - ports: + - port: {{ .Values.containerPorts.external }} + {{- if .Values.externalAccess.from }} + from: {{- include "common.tplvalues.render" ( dict "value" .Values.networkPolicy.externalAccess.from "context" $ ) | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.metrics.kafka.enabled }} + # Allow prometheus scrapes + - ports: + - port: {{ .Values.metrics.kafka.containerPorts.metrics }} + {{- end }} +{{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/controller-poddisruptionbudget.yaml b/deployment/charts/kafka/templates/poddisruptionbudget.yaml similarity index 55% rename from deployment/deployment/nginx-ingress-controller/templates/controller-poddisruptionbudget.yaml rename to deployment/charts/kafka/templates/poddisruptionbudget.yaml index d1e3d44..e0a6015 100644 --- a/deployment/deployment/nginx-ingress-controller/templates/controller-poddisruptionbudget.yaml +++ b/deployment/charts/kafka/templates/poddisruptionbudget.yaml @@ -1,13 +1,14 @@ -{{- if and .Values.pdb.create (eq .Values.kind "Deployment") }} -apiVersion: policy/v1beta1 +{{- $replicaCount := int .Values.replicaCount }} +{{- if and .Values.pdb.create (gt $replicaCount 1) }} +apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} kind: PodDisruptionBudget metadata: - name: {{ template "common.names.fullname" . }} + name: {{ include "common.names.fullname" . }} namespace: {{ .Release.Namespace | quote }} labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: controller + app.kubernetes.io/component: kafka {{- if .Values.commonLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- 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 }} @@ -20,6 +21,6 @@ spec: maxUnavailable: {{ .Values.pdb.maxUnavailable }} {{- end }} selector: - matchLabels: {{- include "common.labels.standard" . | nindent 6 }} - app.kubernetes.io/component: controller + matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: kafka {{- end }} diff --git a/deployment/charts/kafka/templates/prometheusrule.yaml b/deployment/charts/kafka/templates/prometheusrule.yaml new file mode 100644 index 0000000..bce728a --- /dev/null +++ b/deployment/charts/kafka/templates/prometheusrule.yaml @@ -0,0 +1,20 @@ +{{- if and (or .Values.metrics.kafka.enabled .Values.metrics.jmx.enabled) .Values.metrics.prometheusRule.enabled .Values.metrics.prometheusRule.groups }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ include "common.names.fullname" . }} + namespace: {{ default (include "common.names.namespace" .) .Values.metrics.prometheusRule.namespace }} + 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.labels }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.prometheusRule.labels "context" .) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" .) | nindent 4 }} + {{- end }} +spec: + groups: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.prometheusRule.groups "context" .) | nindent 4 }} +{{- end }} diff --git a/deployment/charts/kafka/templates/role.yaml b/deployment/charts/kafka/templates/role.yaml new file mode 100644 index 0000000..63215b3 --- /dev/null +++ b/deployment/charts/kafka/templates/role.yaml @@ -0,0 +1,24 @@ +{{- if .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 }} + app.kubernetes.io/component: kafka + {{- 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: + - services + verbs: + - get + - list + - watch +{{- end -}} diff --git a/deployment/deployment/nginx-ingress-controller/templates/clusterrolebinding.yaml b/deployment/charts/kafka/templates/rolebinding.yaml similarity index 63% rename from deployment/deployment/nginx-ingress-controller/templates/clusterrolebinding.yaml rename to deployment/charts/kafka/templates/rolebinding.yaml index 9d0857d..fb5e3a1 100644 --- a/deployment/deployment/nginx-ingress-controller/templates/clusterrolebinding.yaml +++ b/deployment/charts/kafka/templates/rolebinding.yaml @@ -1,22 +1,23 @@ -{{- if and .Values.rbac.create (not .Values.scope.enabled) -}} +{{- if .Values.rbac.create }} apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: ClusterRoleBinding +kind: RoleBinding metadata: name: {{ include "common.names.fullname" . }} namespace: {{ .Release.Namespace | quote }} labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: kafka {{- if .Values.commonLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- 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 }} roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole + kind: Role name: {{ include "common.names.fullname" . }} + apiGroup: rbac.authorization.k8s.io subjects: - kind: ServiceAccount - name: {{ include "nginx-ingress-controller.serviceAccountName" . }} - namespace: {{ .Release.Namespace | quote }} -{{- end -}} + name: {{ template "kafka.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/deployment/charts/kafka/templates/scripts-configmap.yaml b/deployment/charts/kafka/templates/scripts-configmap.yaml new file mode 100644 index 0000000..57e1250 --- /dev/null +++ b/deployment/charts/kafka/templates/scripts-configmap.yaml @@ -0,0 +1,202 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-scripts" (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 }} +data: + {{- $fullname := include "common.names.fullname" . }} + {{- $releaseNamespace := .Release.Namespace }} + {{- $clusterDomain := .Values.clusterDomain }} + {{- $interBrokerPort := .Values.service.ports.internal }} + {{- $clientPort := .Values.service.ports.client }} + {{- $jksTruststoreSecret := .Values.auth.tls.jksTruststoreSecret -}} + {{- $jksTruststore := .Values.auth.tls.jksTruststore -}} + {{- $jksKeystoreSAN := .Values.auth.tls.jksKeystoreSAN -}} + {{- if .Values.externalAccess.autoDiscovery.enabled }} + auto-discovery.sh: |- + #!/bin/bash + + SVC_NAME="${MY_POD_NAME}-external" + + {{- if eq .Values.externalAccess.service.type "LoadBalancer" }} + # Auxiliary functions + retry_while() { + local -r cmd="${1:?cmd is missing}" + local -r retries="${2:-12}" + local -r sleep_time="${3:-5}" + local return_value=1 + + read -r -a command <<< "$cmd" + for ((i = 1 ; i <= retries ; i+=1 )); do + "${command[@]}" && return_value=0 && break + sleep "$sleep_time" + done + return $return_value + } + k8s_svc_lb_ip() { + local namespace=${1:?namespace is missing} + local service=${2:?service is missing} + local service_ip=$(kubectl get svc "$service" -n "$namespace" -o jsonpath="{.status.loadBalancer.ingress[0].ip}") + local service_hostname=$(kubectl get svc "$service" -n "$namespace" -o jsonpath="{.status.loadBalancer.ingress[0].hostname}") + + if [[ -n ${service_ip} ]]; then + echo "${service_ip}" + else + echo "${service_hostname}" + fi + } + k8s_svc_lb_ip_ready() { + local namespace=${1:?namespace is missing} + local service=${2:?service is missing} + [[ -n "$(k8s_svc_lb_ip "$namespace" "$service")" ]] + } + # Wait until LoadBalancer IP is ready + retry_while "k8s_svc_lb_ip_ready {{ $releaseNamespace }} $SVC_NAME" || exit 1 + # Obtain LoadBalancer external IP + k8s_svc_lb_ip "{{ $releaseNamespace }}" "$SVC_NAME" | tee "$SHARED_FILE" + {{- else if eq .Values.externalAccess.service.type "NodePort" }} + k8s_svc_node_port() { + local namespace=${1:?namespace is missing} + local service=${2:?service is missing} + local index=${3:-0} + local node_port="$(kubectl get svc "$service" -n "$namespace" -o jsonpath="{.spec.ports[$index].nodePort}")" + echo "$node_port" + } + k8s_svc_node_port "{{ $releaseNamespace }}" "$SVC_NAME" | tee "$SHARED_FILE" + {{- end }} + {{- end }} + setup.sh: |- + #!/bin/bash + + ID="${MY_POD_NAME#"{{ $fullname }}-"}" + if [[ -f "{{ .Values.logsDirs | splitList "," | first }}/meta.properties" ]]; then + export KAFKA_CFG_BROKER_ID="$(grep "broker.id" "{{ .Values.logsDirs | splitList "," | first }}/meta.properties" | awk -F '=' '{print $2}')" + else + export KAFKA_CFG_BROKER_ID="$((ID + {{ .Values.minBrokerId }}))" + fi + + {{- if eq .Values.brokerRackAssignment "aws-az" }} + export KAFKA_CFG_BROKER_RACK=$(curl "http://169.254.169.254/latest/meta-data/placement/availability-zone-id") + {{- end }} + + {{- if .Values.externalAccess.enabled }} + # Configure external ip and port + {{- if eq .Values.externalAccess.service.type "LoadBalancer" }} + {{- if .Values.externalAccess.autoDiscovery.enabled }} + export EXTERNAL_ACCESS_HOST="$(<${SHARED_FILE})" + {{- else }} + export EXTERNAL_ACCESS_HOST=$(echo '{{ .Values.externalAccess.service.loadBalancerNames | default .Values.externalAccess.service.loadBalancerIPs }}' | tr -d '[]' | cut -d ' ' -f "$(($ID + 1))") + {{- end }} + export EXTERNAL_ACCESS_PORT={{ .Values.externalAccess.service.ports.external }} + {{- else if eq .Values.externalAccess.service.type "NodePort" }} + {{- if and .Values.externalAccess.service.usePodIPs .Values.externalAccess.autoDiscovery.enabled }} + export EXTERNAL_ACCESS_HOST="${MY_POD_IP}" + {{- else if or .Values.externalAccess.service.useHostIPs .Values.externalAccess.autoDiscovery.enabled }} + export EXTERNAL_ACCESS_HOST="${HOST_IP}" + {{- else if .Values.externalAccess.service.domain }} + export EXTERNAL_ACCESS_HOST={{ .Values.externalAccess.service.domain }} + {{- else }} + export EXTERNAL_ACCESS_HOST=$(curl -s https://ipinfo.io/ip) + {{- end }} + {{- if .Values.externalAccess.autoDiscovery.enabled }} + export EXTERNAL_ACCESS_PORT="$(<${SHARED_FILE})" + {{- else }} + export EXTERNAL_ACCESS_PORT=$(echo '{{ .Values.externalAccess.service.nodePorts }}' | tr -d '[]' | cut -d ' ' -f "$(($ID + 1))") + {{- end }} + {{- else }} + export EXTERNAL_ACCESS_HOST={{ .Values.externalAccess.service.domain }} + export EXTERNAL_ACCESS_PORT="$((ID + {{ .Values.externalAccess.service.ports.external }}))" + {{- end }} + + # Configure Kafka advertised listeners + {{- if .Values.advertisedListeners }} + export KAFKA_CFG_ADVERTISED_LISTENERS={{ join "," .Values.advertisedListeners }} + {{- else }} + export KAFKA_CFG_ADVERTISED_LISTENERS="INTERNAL://${MY_POD_NAME}.{{ $fullname }}-headless.{{ $releaseNamespace }}.svc.{{ $clusterDomain }}:{{ $interBrokerPort }},CLIENT://${MY_POD_NAME}.{{ $fullname }}-headless.{{ $releaseNamespace }}.svc.{{ $clusterDomain }}:{{ $clientPort }},EXTERNAL://${EXTERNAL_ACCESS_HOST}:${EXTERNAL_ACCESS_PORT}" + {{- end }} + {{- end }} + + {{- if (include "kafka.tlsEncryption" .) }} + mkdir -p /opt/bitnami/kafka/config/certs + {{- if eq .Values.auth.tls.type "jks" }} + {{- if not (empty .Values.auth.tls.existingSecrets) }} + JKS_TRUSTSTORE={{ printf "/%s/%s" (ternary "certs-${ID}" "truststore" (empty $jksTruststoreSecret)) (default "kafka.truststore.jks" $jksTruststore) | quote }} + JKS_KEYSTORE={{ printf "/certs-${ID}/%s" (default "kafka.keystore.jks" $jksKeystoreSAN) | quote }} + {{- else }} + JKS_TRUSTSTORE={{ printf "/%s/%s" (ternary "certs" "truststore" (empty $jksTruststoreSecret)) (default "kafka.truststore.jks" $jksTruststore) | quote }} + JKS_KEYSTORE={{ printf "/certs/%s" (default "kafka-${ID}.keystore.jks" $jksKeystoreSAN) | quote }} + {{- end }} + if [[ -f "$JKS_TRUSTSTORE" ]] && [[ -f "$JKS_KEYSTORE" ]]; then + cp "$JKS_TRUSTSTORE" "/opt/bitnami/kafka/config/certs/kafka.truststore.jks" + cp "$JKS_KEYSTORE" "/opt/bitnami/kafka/config/certs/kafka.keystore.jks" + else + echo "Couldn't find the expected Java Key Stores (JKS) files! They are mandatory when encryption via TLS is enabled." + exit 1 + fi + export KAFKA_TLS_TRUSTSTORE_FILE="/opt/bitnami/kafka/config/certs/kafka.truststore.jks" + + {{- else if eq .Values.auth.tls.type "pem" }} + + {{- if or (not (empty .Values.auth.tls.existingSecrets)) .Values.auth.tls.autoGenerated }} + PEM_CA="/certs-${ID}/ca.crt" + PEM_CERT="/certs-${ID}/tls.crt" + PEM_KEY="/certs-${ID}/tls.key" + {{- else }} + PEM_CA="/certs/kafka.truststore.pem" + PEM_CERT="/certs/kafka-${ID}.keystore.pem" + PEM_KEY="/certs/kafka-${ID}.keystore.key" + {{- end }} + if [[ -f "$PEM_CERT" ]] && [[ -f "$PEM_KEY" ]]; then + CERT_DIR="/opt/bitnami/kafka/config/certs" + PEM_CA_LOCATION="${CERT_DIR}/kafka.truststore.pem" + PEM_CERT_LOCATION="${CERT_DIR}/kafka.keystore.pem" + {{- if .Values.auth.tls.pemChainIncluded }} + cat $PEM_CERT | csplit - -s -z '/\-*END CERTIFICATE\-*/+1' '{*}' -f ${CERT_DIR}/xx + FIND_CA_RESULT=$(find ${CERT_DIR} -not -name 'xx00' -name 'xx*') + if [[ $(echo $FIND_CA_RESULT | wc -l) < 1 ]]; then + echo "auth.tls.pemChainIncluded was set, but PEM chain only contained 1 cert" + exit 1 + fi + echo $FIND_CA_RESULT | sort | xargs cat >> "$PEM_CA_LOCATION" + cat ${CERT_DIR}/xx00 > "$PEM_CERT_LOCATION" + {{- else }} + if [[ -f "$PEM_CA" ]]; then + cp "$PEM_CA" "$PEM_CA_LOCATION" + cp "$PEM_CERT" "$PEM_CERT_LOCATION" + else + echo "PEM_CA not provided, and auth.tls.pemChainIncluded was not true. One of these values must be set when using PEM type for TLS." + exit 1 + fi + {{- end }} + + # Ensure the key used PEM format with PKCS#8 + openssl pkcs8 -topk8 -nocrypt -in "$PEM_KEY" > "/opt/bitnami/kafka/config/certs/kafka.keystore.key" + else + echo "Couldn't find the expected PEM files! They are mandatory when encryption via TLS is enabled." + exit 1 + fi + export KAFKA_TLS_TRUSTSTORE_FILE="/opt/bitnami/kafka/config/certs/kafka.truststore.pem" + {{- end }} + {{- end }} + + # Configure zookeeper client + {{- if and (not (empty .Values.auth.zookeeper.tls.existingSecret)) .Values.auth.zookeeper.tls.enabled }} + JKS_TRUSTSTORE={{ printf "/kafka-zookeeper-cert/%s" (.Values.auth.zookeeper.tls.existingSecretTruststoreKey) | quote }} + JKS_KEYSTORE={{ printf "/kafka-zookeeper-cert/%s" (.Values.auth.zookeeper.tls.existingSecretKeystoreKey) | quote }} + if [[ -f "$JKS_TRUSTSTORE" ]] && [[ -f "$JKS_KEYSTORE" ]]; then + CERT_DIR="/opt/bitnami/kafka/config/certs" + TRUSTSTORE_LOCATION="${CERT_DIR}/zookeeper.truststore.jks" + cp "$JKS_TRUSTSTORE" "$TRUSTSTORE_LOCATION" + cp "$JKS_KEYSTORE" "${CERT_DIR}/zookeeper.keystore.jks" + export KAFKA_ZOOKEEPER_TLS_TRUSTSTORE_FILE="${TRUSTSTORE_LOCATION}" + fi + {{- end }} + + exec /entrypoint.sh /run.sh diff --git a/deployment/charts/kafka/templates/serviceaccount.yaml b/deployment/charts/kafka/templates/serviceaccount.yaml new file mode 100644 index 0000000..73091f5 --- /dev/null +++ b/deployment/charts/kafka/templates/serviceaccount.yaml @@ -0,0 +1,20 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "kafka.serviceAccountName" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: kafka + {{- 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.serviceAccount.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.serviceAccount.annotations "context" $ ) | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} +{{- end }} diff --git a/deployment/charts/kafka/templates/servicemonitor-jmx-metrics.yaml b/deployment/charts/kafka/templates/servicemonitor-jmx-metrics.yaml new file mode 100644 index 0000000..1919fee --- /dev/null +++ b/deployment/charts/kafka/templates/servicemonitor-jmx-metrics.yaml @@ -0,0 +1,53 @@ +{{- if and .Values.metrics.jmx.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ printf "%s-jmx-metrics" (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 }} + app.kubernetes.io/component: metrics + {{- if .Values.metrics.serviceMonitor.labels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.labels "context" $ ) | nindent 4 }} + {{- end }} + {{- 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.metrics.serviceMonitor.jobLabel }} + jobLabel: {{ .Values.metrics.serviceMonitor.jobLabel }} + {{- end }} + 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 }} + app.kubernetes.io/component: metrics + endpoints: + - port: http-metrics + path: "/" + {{- 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.relabelings }} + relabelings: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.relabelings "context" $) | nindent 6 }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.metricRelabelings }} + metricRelabelings: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.metricRelabelings "context" $) | nindent 6 }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.honorLabels }} + honorLabels: {{ .Values.metrics.serviceMonitor.honorLabels }} + {{- end }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} +{{- end }} diff --git a/deployment/charts/kafka/templates/servicemonitor-metrics.yaml b/deployment/charts/kafka/templates/servicemonitor-metrics.yaml new file mode 100644 index 0000000..3431946 --- /dev/null +++ b/deployment/charts/kafka/templates/servicemonitor-metrics.yaml @@ -0,0 +1,53 @@ +{{- if and .Values.metrics.kafka.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ printf "%s-metrics" (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 }} + app.kubernetes.io/component: cluster-metrics + {{- if .Values.metrics.serviceMonitor.labels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.labels "context" $ ) | nindent 4 }} + {{- end }} + {{- 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.metrics.serviceMonitor.jobLabel }} + jobLabel: {{ .Values.metrics.serviceMonitor.jobLabel }} + {{- end }} + 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 }} + app.kubernetes.io/component: cluster-metrics + endpoints: + - port: http-metrics + path: "/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.relabelings }} + relabelings: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.relabelings "context" $) | nindent 6 }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.metricRelabelings }} + metricRelabelings: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.metricRelabelings "context" $) | nindent 6 }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.honorLabels }} + honorLabels: {{ .Values.metrics.serviceMonitor.honorLabels }} + {{- end }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} +{{- end }} diff --git a/deployment/charts/kafka/templates/statefulset.yaml b/deployment/charts/kafka/templates/statefulset.yaml new file mode 100644 index 0000000..2146a3d --- /dev/null +++ b/deployment/charts/kafka/templates/statefulset.yaml @@ -0,0 +1,610 @@ +{{- $replicaCount := int .Values.replicaCount }} +{{- $fullname := include "common.names.fullname" . }} +{{- $releaseNamespace := .Release.Namespace }} +{{- $clusterDomain := .Values.clusterDomain }} +{{- $interBrokerPort := .Values.service.ports.internal }} +{{- $clientPort := .Values.service.ports.client }} +{{- $interBrokerProtocol := include "kafka.listenerType" (dict "protocol" .Values.auth.interBrokerProtocol) -}} +{{- $clientProtocol := include "kafka.listenerType" (dict "protocol" .Values.auth.clientProtocol) -}} +{{- $externalClientProtocol := include "kafka.listenerType" (dict "protocol" (include "kafka.externalClientProtocol" . )) -}} +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ include "common.names.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: kafka + {{- 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: + podManagementPolicy: {{ .Values.podManagementPolicy }} + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: kafka + serviceName: {{ printf "%s-headless" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }} + updateStrategy: {{- include "common.tplvalues.render" (dict "value" .Values.updateStrategy "context" $ ) | nindent 4 }} + template: + metadata: + labels: {{- include "common.labels.standard" . | nindent 8 }} + app.kubernetes.io/component: kafka + {{- if .Values.podLabels }} + {{- include "common.tplvalues.render" (dict "value" .Values.podLabels "context" $) | nindent 8 }} + {{- end }} + annotations: + {{- if (include "kafka.createConfigmap" .) }} + checksum/configuration: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- end }} + {{- if (include "kafka.createJaasSecret" .) }} + checksum/jaas-secret: {{ include (print $.Template.BasePath "/jaas-secret.yaml") . | sha256sum }} + {{- end }} + {{- if (include "kafka.createTlsSecret" .) }} + checksum/tls-secret: {{ include (print $.Template.BasePath "/tls-secrets.yaml") . | sha256sum }} + {{- end }} + {{- if .Values.externalAccess.enabled }} + checksum/scripts: {{ include (print $.Template.BasePath "/scripts-configmap.yaml") . | sha256sum }} + {{- end }} + {{- if (include "kafka.metrics.jmx.createConfigmap" .) }} + checksum/jmx-configuration: {{ include (print $.Template.BasePath "/jmx-configmap.yaml") . | sha256sum }} + {{- end }} + {{- if .Values.podAnnotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.podAnnotations "context" $) | nindent 8 }} + {{- end }} + spec: + {{- include "kafka.imagePullSecrets" . | nindent 6 }} + {{- if .Values.hostAliases }} + hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.hostAliases "context" $) | nindent 8 }} + {{- end }} + hostNetwork: {{ .Values.hostNetwork }} + hostIPC: {{ .Values.hostIPC }} + {{- if .Values.schedulerName }} + schedulerName: {{ .Values.schedulerName | quote }} + {{- end }} + {{- if .Values.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAffinityPreset "component" "kafka" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset "component" "kafka" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.nodeAffinityPreset.type "key" .Values.nodeAffinityPreset.key "values" .Values.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.tolerations "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.topologySpreadConstraints }} + topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.topologySpreadConstraints "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} + {{- end }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName }} + {{- end }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "kafka.serviceAccountName" . }} + {{- if or (and .Values.volumePermissions.enabled .Values.persistence.enabled) (and .Values.externalAccess.enabled .Values.externalAccess.autoDiscovery.enabled) .Values.initContainers }} + initContainers: + {{- if and .Values.volumePermissions.enabled .Values.persistence.enabled }} + - name: volume-permissions + image: {{ include "kafka.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + command: + - /bin/bash + args: + - -ec + - | + mkdir -p "{{ .Values.persistence.mountPath }}" "{{ .Values.logPersistence.mountPath }}" + chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} "{{ .Values.persistence.mountPath }}" "{{ .Values.logPersistence.mountPath }}" + find "{{ .Values.persistence.mountPath }}" -mindepth 1 -maxdepth 1 -not -name ".snapshot" -not -name "lost+found" | xargs -r chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} + find "{{ .Values.logPersistence.mountPath }}" -mindepth 1 -maxdepth 1 -not -name ".snapshot" -not -name "lost+found" | xargs -r chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} + {{- if eq ( toString ( .Values.volumePermissions.containerSecurityContext.runAsUser )) "auto" }} + securityContext: {{- omit .Values.volumePermissions.containerSecurityContext "runAsUser" | toYaml | nindent 12 }} + {{- else }} + securityContext: {{- .Values.volumePermissions.containerSecurityContext | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.volumePermissions.resources }} + resources: {{- toYaml .Values.volumePermissions.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: {{ .Values.persistence.mountPath }} + - name: logs + mountPath: {{ .Values.logPersistence.mountPath }} + {{- end }} + {{- if and .Values.externalAccess.enabled .Values.externalAccess.autoDiscovery.enabled }} + - name: auto-discovery + image: {{ include "kafka.externalAccess.autoDiscovery.image" . }} + imagePullPolicy: {{ .Values.externalAccess.autoDiscovery.image.pullPolicy | quote }} + command: + - /scripts/auto-discovery.sh + env: + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: SHARED_FILE + value: "/shared/info.txt" + {{- if .Values.externalAccess.autoDiscovery.resources }} + resources: {{- toYaml .Values.externalAccess.autoDiscovery.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: shared + mountPath: /shared + - name: logs + mountPath: {{ .Values.logPersistence.mountPath }} + - name: scripts + mountPath: /scripts/auto-discovery.sh + subPath: auto-discovery.sh + {{- end }} + {{- if .Values.initContainers }} + {{- include "common.tplvalues.render" ( dict "value" .Values.initContainers "context" $ ) | nindent 8 }} + {{- end }} + {{- end }} + containers: + - name: kafka + image: {{ include "kafka.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy | quote }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.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.command }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.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.args }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.args "context" $) | nindent 12 }} + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" (or .Values.image.debug .Values.diagnosticMode.enabled) | quote }} + - name: MY_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: KAFKA_CFG_ZOOKEEPER_CONNECT + {{- if .Values.zookeeper.enabled }} + value: {{ printf "%s%s" (include "kafka.zookeeper.fullname" .) (tpl .Values.zookeeperChrootPath .) | quote }} + {{- else }} + value: {{ include "common.tplvalues.render" (dict "value" (printf "%s%s" (join "," .Values.externalZookeeper.servers) (tpl .Values.zookeeperChrootPath .)) "context" $) }} + {{- end }} + - name: KAFKA_INTER_BROKER_LISTENER_NAME + value: {{ .Values.interBrokerListenerName | quote }} + - name: KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP + {{- if .Values.listenerSecurityProtocolMap }} + value: {{ .Values.listenerSecurityProtocolMap | quote }} + {{- else if .Values.externalAccess.enabled }} + value: "INTERNAL:{{ $interBrokerProtocol }},CLIENT:{{ $clientProtocol }},EXTERNAL:{{ $externalClientProtocol }}" + {{- else }} + value: "INTERNAL:{{ $interBrokerProtocol }},CLIENT:{{ $clientProtocol }}" + {{- end }} + {{- if or ($clientProtocol | regexFind "SASL") ($externalClientProtocol | regexFind "SASL") ($interBrokerProtocol | regexFind "SASL") .Values.auth.sasl.jaas.zookeeperUser }} + - name: KAFKA_CFG_SASL_ENABLED_MECHANISMS + value: {{ upper .Values.auth.sasl.mechanisms | quote }} + - name: KAFKA_CFG_SASL_MECHANISM_INTER_BROKER_PROTOCOL + value: {{ upper .Values.auth.sasl.interBrokerMechanism | quote }} + {{- end }} + - name: KAFKA_CFG_LISTENERS + {{- if .Values.listeners }} + value: {{ join "," .Values.listeners }} + {{- else if .Values.externalAccess.enabled }} + value: "INTERNAL://:{{ $interBrokerPort }},CLIENT://:9092,EXTERNAL://:9094" + {{- else }} + value: "INTERNAL://:{{ $interBrokerPort }},CLIENT://:9092" + {{- end }} + {{- if .Values.externalAccess.enabled }} + {{- if .Values.externalAccess.autoDiscovery.enabled }} + - name: SHARED_FILE + value: "/shared/info.txt" + {{- end }} + {{- if eq .Values.externalAccess.service.type "NodePort" }} + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- end }} + {{- else }} + - name: KAFKA_CFG_ADVERTISED_LISTENERS + {{- if .Values.advertisedListeners }} + value: {{ join "," .Values.advertisedListeners }} + {{- else }} + value: "INTERNAL://$(MY_POD_NAME).{{ $fullname }}-headless.{{ $releaseNamespace }}.svc.{{ $clusterDomain }}:{{ $interBrokerPort }},CLIENT://$(MY_POD_NAME).{{ $fullname }}-headless.{{ $releaseNamespace }}.svc.{{ $clusterDomain }}:{{ $clientPort }}" + {{- end }} + {{- end }} + - name: ALLOW_PLAINTEXT_LISTENER + value: {{ ternary "yes" "no" .Values.allowPlaintextListener | quote }} + {{- if or (include "kafka.client.saslAuthentication" .) (include "kafka.interBroker.saslAuthentication" .) }} + - name: KAFKA_OPTS + value: "-Djava.security.auth.login.config=/opt/bitnami/kafka/config/kafka_jaas.conf" + {{- if (include "kafka.client.saslAuthentication" .) }} + - name: KAFKA_CLIENT_USERS + value: {{ join "," .Values.auth.sasl.jaas.clientUsers | quote }} + - name: KAFKA_CLIENT_PASSWORDS + valueFrom: + secretKeyRef: + name: {{ include "kafka.jaasSecretName" . }} + key: client-passwords + {{- end }} + {{- if (include "kafka.interBroker.saslAuthentication" .) }} + - name: KAFKA_INTER_BROKER_USER + value: {{ .Values.auth.sasl.jaas.interBrokerUser | quote }} + - name: KAFKA_INTER_BROKER_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "kafka.jaasSecretName" . }} + key: inter-broker-password + {{- end }} + {{- end }} + {{- if and .Values.zookeeper.auth.client.enabled .Values.auth.sasl.jaas.zookeeperUser }} + - name: KAFKA_ZOOKEEPER_USER + value: {{ .Values.auth.sasl.jaas.zookeeperUser | quote }} + - name: KAFKA_ZOOKEEPER_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "kafka.jaasSecretName" . }} + key: zookeeper-password + {{- end }} + - name: KAFKA_ZOOKEEPER_PROTOCOL + value: {{ include "kafka.zookeeper.protocol" . }} + {{- if .Values.auth.zookeeper.tls.enabled }} + - name: KAFKA_ZOOKEEPER_TLS_TYPE + value: {{ upper .Values.auth.zookeeper.tls.type | quote }} + - name: KAFKA_ZOOKEEPER_TLS_VERIFY_HOSTNAME + value: {{ .Values.auth.zookeeper.tls.verifyHostname | quote }} + {{- if .Values.auth.zookeeper.tls.passwordsSecret }} + - name: KAFKA_ZOOKEEPER_TLS_KEYSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.auth.zookeeper.tls.passwordsSecret }} + key: {{ .Values.auth.zookeeper.tls.passwordsSecretKeystoreKey | quote }} + - name: KAFKA_ZOOKEEPER_TLS_TRUSTSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.auth.zookeeper.tls.passwordsSecret }} + key: {{ .Values.auth.zookeeper.tls.passwordsSecretTruststoreKey | quote }} + {{- end }} + {{- end }} + {{- if (include "kafka.tlsEncryption" .) }} + - name: KAFKA_TLS_TYPE + value: {{ upper .Values.auth.tls.type | quote }} + - name: KAFKA_CFG_SSL_ENDPOINT_IDENTIFICATION_ALGORITHM + value: {{ default "" .Values.auth.tls.endpointIdentificationAlgorithm | quote }} + - name: KAFKA_TLS_CLIENT_AUTH + value: {{ ternary "required" "none" (or (eq (include "kafka.externalClientProtocol" . ) "mtls") (eq .Values.auth.clientProtocol "mtls")) | quote }} + - name: KAFKA_CERTIFICATE_PASSWORD + {{- if .Values.auth.tls.existingSecret }} + valueFrom: + secretKeyRef: + name: {{ .Values.auth.tls.existingSecret }} + key: password + {{- else }} + value: {{ default "" .Values.auth.tls.password | quote }} + {{- end }} + {{- end }} + {{- if .Values.metrics.jmx.enabled }} + - name: JMX_PORT + value: "5555" + {{- end }} + - name: KAFKA_VOLUME_DIR + value: {{ .Values.persistence.mountPath | quote }} + - name: KAFKA_LOG_DIR + value: {{ .Values.logPersistence.mountPath | quote }} + - name: KAFKA_CFG_DELETE_TOPIC_ENABLE + value: {{ .Values.deleteTopicEnable | quote }} + - name: KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE + value: {{ .Values.autoCreateTopicsEnable | quote }} + - name: KAFKA_HEAP_OPTS + value: {{ .Values.heapOpts | quote }} + - name: KAFKA_CFG_LOG_FLUSH_INTERVAL_MESSAGES + value: {{ .Values.logFlushIntervalMessages | replace "_" "" | quote }} + - name: KAFKA_CFG_LOG_FLUSH_INTERVAL_MS + value: {{ .Values.logFlushIntervalMs | quote }} + - name: KAFKA_CFG_LOG_RETENTION_BYTES + value: {{ .Values.logRetentionBytes | replace "_" "" | quote }} + - name: KAFKA_CFG_LOG_RETENTION_CHECK_INTERVAL_MS + value: {{ .Values.logRetentionCheckIntervalMs | quote }} + - name: KAFKA_CFG_LOG_RETENTION_HOURS + value: {{ .Values.logRetentionHours | quote }} + - name: KAFKA_CFG_MESSAGE_MAX_BYTES + value: {{ .Values.maxMessageBytes | replace "_" "" | quote }} + - name: KAFKA_CFG_LOG_SEGMENT_BYTES + value: {{ .Values.logSegmentBytes | replace "_" "" | quote }} + - name: KAFKA_CFG_LOG_DIRS + value: {{ .Values.logsDirs | quote }} + - name: KAFKA_CFG_DEFAULT_REPLICATION_FACTOR + value: {{ .Values.defaultReplicationFactor | quote }} + - name: KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR + value: {{ .Values.offsetsTopicReplicationFactor | quote }} + - name: KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR + value: {{ .Values.transactionStateLogReplicationFactor | quote }} + - name: KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR + value: {{ .Values.transactionStateLogMinIsr | quote }} + - name: KAFKA_CFG_NUM_IO_THREADS + value: {{ .Values.numIoThreads | quote }} + - name: KAFKA_CFG_NUM_NETWORK_THREADS + value: {{ .Values.numNetworkThreads | quote }} + - name: KAFKA_CFG_NUM_PARTITIONS + value: {{ .Values.numPartitions | quote }} + - name: KAFKA_CFG_NUM_RECOVERY_THREADS_PER_DATA_DIR + value: {{ .Values.numRecoveryThreadsPerDataDir | quote }} + - name: KAFKA_CFG_SOCKET_RECEIVE_BUFFER_BYTES + value: {{ .Values.socketReceiveBufferBytes | quote }} + - name: KAFKA_CFG_SOCKET_REQUEST_MAX_BYTES + value: {{ .Values.socketRequestMaxBytes | replace "_" "" | quote }} + - name: KAFKA_CFG_SOCKET_SEND_BUFFER_BYTES + value: {{ .Values.socketSendBufferBytes | quote }} + - name: KAFKA_CFG_ZOOKEEPER_CONNECTION_TIMEOUT_MS + value: {{ .Values.zookeeperConnectionTimeoutMs | quote }} + - name: KAFKA_CFG_AUTHORIZER_CLASS_NAME + value: {{ .Values.authorizerClassName | quote }} + - name: KAFKA_CFG_ALLOW_EVERYONE_IF_NO_ACL_FOUND + value: {{ .Values.allowEveryoneIfNoAclFound | quote }} + - name: KAFKA_CFG_SUPER_USERS + value: {{ .Values.superUsers | quote }} + {{- if .Values.extraEnvVars }} + {{- include "common.tplvalues.render" ( dict "value" .Values.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + {{- if or .Values.extraEnvVarsCM .Values.extraEnvVarsSecret }} + envFrom: + {{- if .Values.extraEnvVarsCM }} + - configMapRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsCM "context" $) }} + {{- end }} + {{- if .Values.extraEnvVarsSecret }} + - secretRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsSecret "context" $) }} + {{- end }} + {{- end }} + ports: + - name: kafka-client + containerPort: {{ .Values.containerPorts.client }} + - name: kafka-internal + containerPort: {{ .Values.containerPorts.internal }} + {{- if .Values.externalAccess.enabled }} + - name: kafka-external + containerPort: {{ .Values.containerPorts.external }} + {{- end }} + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customLivenessProbe "context" $) | nindent 12 }} + {{- else if .Values.livenessProbe.enabled }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.livenessProbe "enabled") "context" $) | nindent 12 }} + tcpSocket: + port: kafka-client + {{- end }} + {{- if .Values.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 12 }} + {{- else if .Values.readinessProbe.enabled }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.readinessProbe "enabled") "context" $) | nindent 12 }} + tcpSocket: + port: kafka-client + {{- end }} + {{- if .Values.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.startupProbe.enabled }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.startupProbe "enabled") "context" $) | nindent 12 }} + tcpSocket: + port: kafka-client + {{- end }} + {{- end }} + {{- if .Values.lifecycleHooks }} + lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.lifecycleHooks "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.resources }} + resources: {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: {{ .Values.persistence.mountPath }} + - name: logs + mountPath: {{ .Values.logPersistence.mountPath }} + {{- if or .Values.config .Values.existingConfigmap }} + - name: kafka-config + mountPath: {{ .Values.persistence.mountPath }}/config/server.properties + subPath: server.properties + {{- end }} + {{- if or .Values.log4j .Values.existingLog4jConfigMap }} + - name: log4j-config + mountPath: {{ .Values.persistence.mountPath }}/config/log4j.properties + subPath: log4j.properties + {{- end }} + - name: scripts + mountPath: /scripts/setup.sh + subPath: setup.sh + {{- if and .Values.externalAccess.enabled .Values.externalAccess.autoDiscovery.enabled }} + - name: shared + mountPath: /shared + {{- end }} + {{- if (include "kafka.tlsEncryption" .) }} + {{- if not (empty .Values.auth.tls.existingSecrets) }} + {{- range $index, $_ := .Values.auth.tls.existingSecrets }} + - name: kafka-certs-{{ $index }} + mountPath: /certs-{{ $index }} + readOnly: true + {{- end }} + {{- else if .Values.auth.tls.autoGenerated }} + {{- range $index := until $replicaCount }} + - name: kafka-certs-{{ $index }} + mountPath: /certs-{{ $index }} + readOnly: true + {{- end }} + {{- end }} + {{- if and .Values.auth.zookeeper.tls.enabled .Values.auth.zookeeper.tls.existingSecret }} + - name: kafka-zookeeper-cert + mountPath: /kafka-zookeeper-cert + readOnly: true + {{- end }} + {{- if .Values.auth.tls.jksTruststoreSecret }} + - name: kafka-truststore + mountPath: /truststore + readOnly: true + {{- end }} + {{- end }} + {{- if .Values.extraVolumeMounts }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraVolumeMounts "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.metrics.jmx.enabled }} + - name: jmx-exporter + image: {{ include "kafka.metrics.jmx.image" . }} + imagePullPolicy: {{ .Values.metrics.jmx.image.pullPolicy | quote }} + {{- if .Values.metrics.jmx.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.metrics.jmx.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- 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: + - java + args: + - -XX:MaxRAMPercentage=100 + - -XshowSettings:vm + - -jar + - jmx_prometheus_httpserver.jar + - "5556" + - /etc/jmx-kafka/jmx-kafka-prometheus.yml + {{- end }} + ports: + - name: metrics + containerPort: {{ .Values.metrics.jmx.containerPorts.metrics }} + {{- if .Values.metrics.jmx.resources }} + resources: {{- toYaml .Values.metrics.jmx.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: jmx-config + mountPath: /etc/jmx-kafka + {{- end }} + {{- if .Values.sidecars }} + {{- include "common.tplvalues.render" (dict "value" .Values.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + {{- if or .Values.config .Values.existingConfigmap }} + - name: kafka-config + configMap: + name: {{ include "kafka.configmapName" . }} + {{- end }} + {{- if or .Values.log4j .Values.existingLog4jConfigMap }} + - name: log4j-config + configMap: + name: {{ include "kafka.log4j.configMapName" . }} + {{ end }} + - name: scripts + configMap: + name: {{ include "common.names.fullname" . }}-scripts + defaultMode: 0755 + {{- if and .Values.externalAccess.enabled .Values.externalAccess.autoDiscovery.enabled }} + - name: shared + emptyDir: {} + {{- end }} + {{- if .Values.metrics.jmx.enabled }} + - name: jmx-config + configMap: + name: {{ include "kafka.metrics.jmx.configmapName" . }} + {{- end }} + {{- if (include "kafka.tlsEncryption" .) }} + {{- if not (empty .Values.auth.tls.existingSecrets) }} + {{- range $index, $secret := .Values.auth.tls.existingSecrets }} + - name: kafka-certs-{{ $index }} + secret: + secretName: {{ tpl $secret $ }} + defaultMode: 256 + {{- end }} + {{- else if .Values.auth.tls.autoGenerated }} + {{- range $index := until $replicaCount }} + - name: kafka-certs-{{ $index }} + secret: + secretName: {{ printf "%s-%d-tls" (include "common.names.fullname" $) $index }} + defaultMode: 256 + {{- end }} + {{- end }} + {{- if and .Values.auth.zookeeper.tls.enabled .Values.auth.zookeeper.tls.existingSecret }} + - name: kafka-zookeeper-cert + secret: + secretName: {{ .Values.auth.zookeeper.tls.existingSecret }} + defaultMode: 256 + {{- end }} + {{- if .Values.auth.tls.jksTruststoreSecret }} + - name: kafka-truststore + secret: + secretName: {{ .Values.auth.tls.jksTruststoreSecret }} + defaultMode: 256 + {{- end }} + {{- end }} + {{- if .Values.extraVolumes }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraVolumes "context" $) | nindent 8 }} + {{- end }} +{{- if not .Values.persistence.enabled }} + - name: data + emptyDir: {} +{{- else if .Values.persistence.existingClaim }} + - name: data + persistentVolumeClaim: + claimName: {{ printf "%s" (tpl .Values.persistence.existingClaim .) }} +{{- end }} +{{- if not .Values.logPersistence.enabled }} + - name: logs + emptyDir: {} +{{- else if .Values.logPersistence.existingClaim }} + - name: logs + persistentVolumeClaim: + claimName: {{ printf "%s" (tpl .Values.logPersistence.existingClaim .) }} +{{- end }} + {{- if or (and .Values.persistence.enabled (not .Values.persistence.existingClaim)) (and .Values.logPersistence.enabled (not .Values.logPersistence.existingClaim)) }} + volumeClaimTemplates: + {{- end }} +{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} + - metadata: + name: data + {{- if .Values.persistence.annotations }} + annotations: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.annotations "context" $) | nindent 10 }} + {{- end }} + {{- if .Values.persistence.labels }} + labels: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.labels "context" $) | nindent 10 }} + {{- end }} + spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{ include "kafka.storageClass" . | nindent 8 }} + {{- if .Values.persistence.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.selector "context" $) | nindent 10 }} + {{- end -}} +{{- end }} +{{- if and .Values.logPersistence.enabled (not .Values.logPersistence.existingClaim) }} + - metadata: + name: logs + {{- if .Values.logPersistence.annotations }} + annotations: {{- include "common.tplvalues.render" (dict "value" .Values.logPersistence.annotations "context" $) | nindent 10 }} + {{- end }} + spec: + accessModes: + {{- range .Values.logPersistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.logPersistence.size | quote }} + {{ include "kafka.storageClass" . | nindent 8 }} + {{- if .Values.logPersistence.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.logPersistence.selector "context" $) | nindent 10 }} + {{- end -}} +{{- end }} diff --git a/deployment/charts/kafka/templates/svc-external-access.yaml b/deployment/charts/kafka/templates/svc-external-access.yaml new file mode 100644 index 0000000..8d77a47 --- /dev/null +++ b/deployment/charts/kafka/templates/svc-external-access.yaml @@ -0,0 +1,63 @@ +{{- if .Values.externalAccess.enabled }} +{{- $fullName := include "common.names.fullname" . }} +{{- $replicaCount := .Values.replicaCount | int }} +{{- $root := . }} + +{{- range $i, $e := until $replicaCount }} +{{- $targetPod := printf "%s-%d" (printf "%s" $fullName) $i }} +{{- $_ := set $ "targetPod" $targetPod }} +apiVersion: v1 +kind: Service +metadata: + name: {{ printf "%s-%d-external" (include "common.names.fullname" $) $i | trunc 63 | trimSuffix "-" }} + namespace: {{ $root.Release.Namespace | quote }} + labels: {{- include "common.labels.standard" $ | nindent 4 }} + app.kubernetes.io/component: kafka + pod: {{ $targetPod }} + {{- if $root.Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" $root.Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if $root.Values.externalAccess.service.labels }} + {{- include "common.tplvalues.render" ( dict "value" $root.Values.externalAccess.service.labels "context" $) | nindent 4 }} + {{- end }} + {{- if or $root.Values.externalAccess.service.annotations $root.Values.commonAnnotations $root.Values.externalAccess.service.loadBalancerAnnotations }} + annotations: + {{- if and (not (empty $root.Values.externalAccess.service.loadBalancerAnnotations)) (eq (len $root.Values.externalAccess.service.loadBalancerAnnotations) $replicaCount) }} + {{ include "common.tplvalues.render" ( dict "value" (index $root.Values.externalAccess.service.loadBalancerAnnotations $i) "context" $) | nindent 4 }} + {{- end }} + {{- if $root.Values.externalAccess.service.annotations }} + {{- include "common.tplvalues.render" ( dict "value" $root.Values.externalAccess.service.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if $root.Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" $root.Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: {{ $root.Values.externalAccess.service.type }} + {{- if eq $root.Values.externalAccess.service.type "LoadBalancer" }} + {{- if and (not (empty $root.Values.externalAccess.service.loadBalancerIPs)) (eq (len $root.Values.externalAccess.service.loadBalancerIPs) $replicaCount) }} + loadBalancerIP: {{ index $root.Values.externalAccess.service.loadBalancerIPs $i }} + {{- end }} + {{- if $root.Values.externalAccess.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: {{- toYaml $root.Values.externalAccess.service.loadBalancerSourceRanges | nindent 4 }} + {{- end }} + {{- end }} + publishNotReadyAddresses: {{ $root.Values.externalAccess.service.publishNotReadyAddresses }} + ports: + - name: tcp-kafka + port: {{ $root.Values.externalAccess.service.ports.external }} + {{- if not (empty $root.Values.externalAccess.service.nodePorts) }} + nodePort: {{ index $root.Values.externalAccess.service.nodePorts $i }} + {{- else }} + nodePort: null + {{- end }} + targetPort: kafka-external + {{- if $root.Values.externalAccess.service.extraPorts }} + {{- include "common.tplvalues.render" (dict "value" $root.Values.externalAccess.service.extraPorts "context" $) | nindent 4 }} + {{- end }} + selector: {{- include "common.labels.matchLabels" $ | nindent 4 }} + app.kubernetes.io/component: kafka + statefulset.kubernetes.io/pod-name: {{ $targetPod }} +--- +{{- end }} +{{- end }} diff --git a/deployment/charts/kafka/templates/svc-headless.yaml b/deployment/charts/kafka/templates/svc-headless.yaml new file mode 100644 index 0000000..af46212 --- /dev/null +++ b/deployment/charts/kafka/templates/svc-headless.yaml @@ -0,0 +1,37 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ printf "%s-headless" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: kafka + {{- if .Values.service.headless.labels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.service.headless.labels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if or .Values.service.headless.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.service.headless.annotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.service.headless.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: ClusterIP + clusterIP: None + publishNotReadyAddresses: {{ .Values.service.headless.publishNotReadyAddresses }} + ports: + - name: tcp-client + port: {{ .Values.service.ports.client }} + protocol: TCP + targetPort: kafka-client + - name: tcp-internal + port: {{ .Values.service.ports.internal }} + protocol: TCP + targetPort: kafka-internal + selector: {{- include "common.labels.matchLabels" . | nindent 4 }} + app.kubernetes.io/component: kafka diff --git a/deployment/charts/kafka/templates/svc.yaml b/deployment/charts/kafka/templates/svc.yaml new file mode 100644 index 0000000..8e0472a --- /dev/null +++ b/deployment/charts/kafka/templates/svc.yaml @@ -0,0 +1,63 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "common.names.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: kafka + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if or .Values.service.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.service.annotations }} + {{ include "common.tplvalues.render" ( dict "value" .Values.service.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: {{ .Values.service.type }} + {{- if and .Values.service.clusterIP (eq .Values.service.type "ClusterIP") }} + clusterIP: {{ .Values.service.clusterIP }} + {{- end }} + {{- if or (eq .Values.service.type "LoadBalancer") (eq .Values.service.type "NodePort") }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy | quote }} + {{- end }} + {{- if and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerSourceRanges)) }} + loadBalancerSourceRanges: {{ .Values.service.loadBalancerSourceRanges }} + {{- end }} + {{- if and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerIP)) }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + {{- if .Values.service.sessionAffinity }} + sessionAffinity: {{ .Values.service.sessionAffinity }} + {{- end }} + {{- if .Values.service.sessionAffinityConfig }} + sessionAffinityConfig: {{- include "common.tplvalues.render" (dict "value" .Values.service.sessionAffinityConfig "context" $) | nindent 4 }} + {{- end }} + ports: + - name: tcp-client + port: {{ .Values.service.ports.client }} + protocol: TCP + targetPort: kafka-client + {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.client)) }} + nodePort: {{ .Values.service.nodePorts.client }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + {{- if .Values.externalAccess.enabled }} + - name: tcp-external + port: {{ .Values.service.ports.external }} + protocol: TCP + targetPort: kafka-external + {{- if (not (empty .Values.service.nodePorts.external)) }} + nodePort: {{ .Values.service.nodePorts.external }} + {{- end }} + {{- end }} + {{- if .Values.service.extraPorts }} + {{- include "common.tplvalues.render" (dict "value" .Values.service.extraPorts "context" $) | nindent 4 }} + {{- end }} + selector: {{- include "common.labels.matchLabels" . | nindent 4 }} + app.kubernetes.io/component: kafka diff --git a/deployment/charts/kafka/templates/tls-secrets.yaml b/deployment/charts/kafka/templates/tls-secrets.yaml new file mode 100644 index 0000000..fdf350e --- /dev/null +++ b/deployment/charts/kafka/templates/tls-secrets.yaml @@ -0,0 +1,30 @@ +{{- if (include "kafka.createTlsSecret" .) }} +{{- $replicaCount := int .Values.replicaCount }} +{{- $releaseNamespace := .Release.Namespace }} +{{- $clusterDomain := .Values.clusterDomain }} +{{- $fullname := include "common.names.fullname" . }} +{{- $ca := genCA "kafka-ca" 365 }} +{{- range $i := until $replicaCount }} +{{- $replicaHost := printf "%s-%d.%s-headless" $fullname $i $fullname }} +{{- $altNames := list (printf "%s.%s.svc.%s" $replicaHost $releaseNamespace $clusterDomain) (printf "%s.%s.svc.%s" $fullname $releaseNamespace $clusterDomain) (printf "%s.%s" $replicaHost $releaseNamespace) (printf "%s.%s" $fullname $releaseNamespace) $replicaHost $fullname }} +{{- $cert := genSignedCert $replicaHost nil $altNames 365 $ca }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ printf "%s-%d-tls" (include "common.names.fullname" $) $i }} + 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: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $cert.Cert | b64enc | quote }} + tls.key: {{ $cert.Key | b64enc | quote }} +--- +{{- end }} +{{- end }} diff --git a/deployment/charts/kafka/values.yaml b/deployment/charts/kafka/values.yaml new file mode 100644 index 0000000..98fdf20 --- /dev/null +++ b/deployment/charts/kafka/values.yaml @@ -0,0 +1,1752 @@ +## @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 StorageClass for Persistent Volume(s) +## +global: + imageRegistry: "" + ## E.g. + ## imagePullSecrets: + ## - myRegistryKeySecretName + ## + imagePullSecrets: [] + storageClass: "" + +## @section Common parameters + +## @param kubeVersion Override Kubernetes version +## +kubeVersion: "" +## @param nameOverride String to partially override common.names.fullname +## +nameOverride: "" +## @param fullnameOverride String to fully override common.names.fullname +## +fullnameOverride: "" +## @param clusterDomain Default Kubernetes cluster domain +## +clusterDomain: cluster.local +## @param commonLabels Labels to add to all deployed objects +## +commonLabels: {} +## @param commonAnnotations Annotations to add to all deployed objects +## +commonAnnotations: {} +## @param extraDeploy Array of extra objects to deploy with the release +## +extraDeploy: [] +## Enable diagnostic mode in the statefulset +## +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 statefulset + ## + command: + - sleep + ## @param diagnosticMode.args Args to override all containers in the statefulset + ## + args: + - infinity + +## @section Kafka parameters + +## Bitnami Kafka image version +## ref: https://hub.docker.com/r/bitnami/kafka/tags/ +## @param image.registry Kafka image registry +## @param image.repository Kafka image repository +## @param image.tag Kafka image tag (immutable tags are recommended) +## @param image.digest Kafka image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag +## @param image.pullPolicy Kafka image pull policy +## @param image.pullSecrets Specify docker-registry secret names as an array +## @param image.debug Specify if debug values should be set +## +image: + registry: docker.io + repository: bitnami/kafka + tag: 3.3.1-debian-11-r25 + 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/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## Set to true if you would like to see extra information on logs + ## + debug: false +## @param config Configuration file for Kafka. Auto-generated based on other parameters when not specified +## Specify content for server.properties +## NOTE: This will override any KAFKA_CFG_ environment variables (including those set by the chart) +## The server.properties is auto-generated based on other parameters when this parameter is not specified +## e.g: +## config: |- +## broker.id=-1 +## listeners=PLAINTEXT://:9092 +## advertised.listeners=PLAINTEXT://KAFKA_IP:9092 +## num.network.threads=3 +## num.io.threads=8 +## socket.send.buffer.bytes=102400 +## socket.receive.buffer.bytes=102400 +## socket.request.max.bytes=104857600 +## log.dirs=/bitnami/kafka/data +## num.partitions=1 +## num.recovery.threads.per.data.dir=1 +## offsets.topic.replication.factor=1 +## transaction.state.log.replication.factor=1 +## transaction.state.log.min.isr=1 +## log.flush.interval.messages=10000 +## log.flush.interval.ms=1000 +## log.retention.hours=168 +## log.retention.bytes=1073741824 +## log.segment.bytes=1073741824 +## log.retention.check.interval.ms=300000 +## zookeeper.connect=ZOOKEEPER_SERVICE_NAME +## zookeeper.connection.timeout.ms=6000 +## group.initial.rebalance.delay.ms=0 +## +config: "" +## @param existingConfigmap ConfigMap with Kafka Configuration +## NOTE: This will override `config` AND any KAFKA_CFG_ environment variables +## +existingConfigmap: "" +## @param log4j An optional log4j.properties file to overwrite the default of the Kafka brokers +## An optional log4j.properties file to overwrite the default of the Kafka brokers +## ref: https://github.com/apache/kafka/blob/trunk/config/log4j.properties +## +log4j: "" +## @param existingLog4jConfigMap The name of an existing ConfigMap containing a log4j.properties file +## The name of an existing ConfigMap containing a log4j.properties file +## NOTE: this will override `log4j` +## +existingLog4jConfigMap: "" +## @param heapOpts Kafka Java Heap size +## +heapOpts: -Xmx1024m -Xms1024m +## @param deleteTopicEnable Switch to enable topic deletion or not +## +deleteTopicEnable: false +## @param autoCreateTopicsEnable Switch to enable auto creation of topics. Enabling auto creation of topics not recommended for production or similar environments +## +autoCreateTopicsEnable: true +## @param logFlushIntervalMessages The number of messages to accept before forcing a flush of data to disk +## +logFlushIntervalMessages: _10000 +## @param logFlushIntervalMs The maximum amount of time a message can sit in a log before we force a flush +## +logFlushIntervalMs: 1000 +## @param logRetentionBytes A size-based retention policy for logs +## +logRetentionBytes: _1073741824 +## @param logRetentionCheckIntervalMs The interval at which log segments are checked to see if they can be deleted +## +logRetentionCheckIntervalMs: 300000 +## @param logRetentionHours The minimum age of a log file to be eligible for deletion due to age +## +logRetentionHours: 168 +## @param logSegmentBytes The maximum size of a log segment file. When this size is reached a new log segment will be created +## +logSegmentBytes: _1073741824 +## @param logsDirs A comma separated list of directories in which kafka's log data is kept +## ref: https://kafka.apache.org/documentation/#brokerconfigs_log.dirs +logsDirs: /bitnami/kafka/data +## @param maxMessageBytes The largest record batch size allowed by Kafka +## +maxMessageBytes: _1000012 +## @param defaultReplicationFactor Default replication factors for automatically created topics +## +defaultReplicationFactor: 1 +## @param offsetsTopicReplicationFactor The replication factor for the offsets topic +## +offsetsTopicReplicationFactor: 1 +## @param transactionStateLogReplicationFactor The replication factor for the transaction topic +## +transactionStateLogReplicationFactor: 1 +## @param transactionStateLogMinIsr Overridden min.insync.replicas config for the transaction topic +## +transactionStateLogMinIsr: 1 +## @param numIoThreads The number of threads doing disk I/O +## +numIoThreads: 8 +## @param numNetworkThreads The number of threads handling network requests +## +numNetworkThreads: 3 +## @param numPartitions The default number of log partitions per topic +## +numPartitions: 1 +## @param numRecoveryThreadsPerDataDir The number of threads per data directory to be used for log recovery at startup and flushing at shutdown +## +numRecoveryThreadsPerDataDir: 1 +## @param socketReceiveBufferBytes The receive buffer (SO_RCVBUF) used by the socket server +## +socketReceiveBufferBytes: 102400 +## @param socketRequestMaxBytes The maximum size of a request that the socket server will accept (protection against OOM) +## +socketRequestMaxBytes: _104857600 +## @param socketSendBufferBytes The send buffer (SO_SNDBUF) used by the socket server +## +socketSendBufferBytes: 102400 +## @param zookeeperConnectionTimeoutMs Timeout in ms for connecting to ZooKeeper +## +zookeeperConnectionTimeoutMs: 6000 +## @param zookeeperChrootPath Path which puts data under some path in the global ZooKeeper namespace +## ref: https://kafka.apache.org/documentation/#brokerconfigs_zookeeper.connect +## +zookeeperChrootPath: "" +## @param authorizerClassName The Authorizer is configured by setting authorizer.class.name=kafka.security.authorizer.AclAuthorizer in server.properties +## +authorizerClassName: "" +## @param allowEveryoneIfNoAclFound By default, if a resource has no associated ACLs, then no one is allowed to access that resource except super users +## +allowEveryoneIfNoAclFound: true +## @param superUsers You can add super users in server.properties +## +superUsers: User:admin +## Authentication parameters +## https://github.com/bitnami/containers/tree/main/bitnami/kafka#security +## +auth: + ## Authentication protocol for client and inter-broker communications + ## This table shows the security provided on each protocol: + ## | Method | Authentication | Encryption via TLS | + ## | plaintext | None | No | + ## | tls | None | Yes | + ## | mtls | Yes (two-way authentication) | Yes | + ## | sasl | Yes (via SASL) | No | + ## | sasl_tls | Yes (via SASL) | Yes | + ## @param auth.clientProtocol Authentication protocol for communications with clients. Allowed protocols: `plaintext`, `tls`, `mtls`, `sasl` and `sasl_tls` + ## @param auth.externalClientProtocol Authentication protocol for communications with external clients. Defaults to value of `auth.clientProtocol`. Allowed protocols: `plaintext`, `tls`, `mtls`, `sasl` and `sasl_tls` + ## @param auth.interBrokerProtocol Authentication protocol for inter-broker communications. Allowed protocols: `plaintext`, `tls`, `mtls`, `sasl` and `sasl_tls` + ## + clientProtocol: plaintext + # Note: empty by default for backwards compatibility reasons, find more information at + # https://github.com/bitnami/charts/pull/8902/ + externalClientProtocol: "" + interBrokerProtocol: plaintext + ## SASL configuration + ## + sasl: + ## @param auth.sasl.mechanisms SASL mechanisms when either `auth.interBrokerProtocol`, `auth.clientProtocol` or `auth.externalClientProtocol` are `sasl`. Allowed types: `plain`, `scram-sha-256`, `scram-sha-512` + ## + mechanisms: plain,scram-sha-256,scram-sha-512 + ## @param auth.sasl.interBrokerMechanism SASL mechanism for inter broker communication. + ## + interBrokerMechanism: plain + ## JAAS configuration for SASL authentication. + ## + jaas: + ## @param auth.sasl.jaas.clientUsers Kafka client user list + ## + ## clientUsers: + ## - user1 + ## - user2 + ## + clientUsers: + - user + ## @param auth.sasl.jaas.clientPasswords Kafka client passwords. This is mandatory if more than one user is specified in clientUsers + ## + ## clientPasswords: + ## - password1 + ## - password2" + ## + clientPasswords: [] + ## @param auth.sasl.jaas.interBrokerUser Kafka inter broker communication user for SASL authentication + ## + interBrokerUser: admin + ## @param auth.sasl.jaas.interBrokerPassword Kafka inter broker communication password for SASL authentication + ## + interBrokerPassword: "" + ## @param auth.sasl.jaas.zookeeperUser Kafka ZooKeeper user for SASL authentication + ## + zookeeperUser: "" + ## @param auth.sasl.jaas.zookeeperPassword Kafka ZooKeeper password for SASL authentication + ## + zookeeperPassword: "" + ## @param auth.sasl.jaas.existingSecret Name of the existing secret containing credentials for clientUsers, interBrokerUser and zookeeperUser + ## Create this secret running the command below where SECRET_NAME is the name of the secret you want to create: + ## kubectl create secret generic SECRET_NAME --from-literal=client-passwords=CLIENT_PASSWORD1,CLIENT_PASSWORD2 --from-literal=inter-broker-password=INTER_BROKER_PASSWORD --from-literal=zookeeper-password=ZOOKEEPER_PASSWORD + ## + existingSecret: "" + ## TLS configuration + ## + tls: + ## @param auth.tls.type Format to use for TLS certificates. Allowed types: `jks` and `pem` + ## + type: jks + ## @param auth.tls.pemChainIncluded Flag to denote that the Certificate Authority (CA) certificates are bundled with the endpoint cert. + ## Certificates must be in proper order, where the top certificate is the leaf and the bottom certificate is the top-most intermediate CA. + ## + pemChainIncluded: false + ## @param auth.tls.existingSecrets Array existing secrets containing the TLS certificates for the Kafka brokers + ## When using 'jks' format for certificates, each secret should contain a truststore and a keystore. + ## Create these secrets following the steps below: + ## 1) Generate your truststore and keystore files. Helpful script: https://raw.githubusercontent.com/confluentinc/confluent-platform-security-tools/master/kafka-generate-ssl.sh + ## 2) Rename your truststore to `kafka.truststore.jks`. + ## 3) Rename your keystores to `kafka-X.keystore.jks` where X is the ID of each Kafka broker. + ## 4) Run the command below one time per broker to create its associated secret (SECRET_NAME_X is the name of the secret you want to create): + ## kubectl create secret generic SECRET_NAME_0 --from-file=kafka.truststore.jks=./kafka.truststore.jks --from-file=kafka.keystore.jks=./kafka-0.keystore.jks + ## kubectl create secret generic SECRET_NAME_1 --from-file=kafka.truststore.jks=./kafka.truststore.jks --from-file=kafka.keystore.jks=./kafka-1.keystore.jks + ## ... + ## + ## When using 'pem' format for certificates, each secret should contain a public CA certificate, a public certificate and one private key. + ## Create these secrets following the steps below: + ## 1) Create a certificate key and signing request per Kafka broker, and sign the signing request with your CA + ## 2) Rename your CA file to `kafka.ca.crt`. + ## 3) Rename your certificates to `kafka-X.tls.crt` where X is the ID of each Kafka broker. + ## 3) Rename your keys to `kafka-X.tls.key` where X is the ID of each Kafka broker. + ## 4) Run the command below one time per broker to create its associated secret (SECRET_NAME_X is the name of the secret you want to create): + ## kubectl create secret generic SECRET_NAME_0 --from-file=ca.crt=./kafka.ca.crt --from-file=tls.crt=./kafka-0.tls.crt --from-file=tls.key=./kafka-0.tls.key + ## kubectl create secret generic SECRET_NAME_1 --from-file=ca.crt=./kafka.ca.crt --from-file=tls.crt=./kafka-1.tls.crt --from-file=tls.key=./kafka-1.tls.key + ## ... + ## + existingSecrets: [] + ## @param auth.tls.autoGenerated Generate automatically self-signed TLS certificates for Kafka brokers. Currently only supported if `auth.tls.type` is `pem` + ## Note: ignored when using 'jks' format or `auth.tls.existingSecrets` is not empty + ## + autoGenerated: false + ## @param auth.tls.password Password to access the JKS files or PEM key when they are password-protected. + ## Note: ignored when using 'existingSecret'. + ## + password: "" + ## @param auth.tls.existingSecret Name of the secret containing the password to access the JKS files or PEM key when they are password-protected. (`key`: `password`) + ## + existingSecret: "" + ## @param auth.tls.jksTruststoreSecret Name of the existing secret containing your truststore if truststore not existing or different from the ones in the `auth.tls.existingSecrets` + ## Note: ignored when using 'pem' format for certificates. + ## + jksTruststoreSecret: "" + ## @param auth.tls.jksKeystoreSAN The secret key from the `auth.tls.existingSecrets` containing the keystore with a SAN certificate + ## The SAN certificate in it should be issued with Subject Alternative Names for all headless services: + ## - kafka-0.kafka-headless.kafka.svc.cluster.local + ## - kafka-1.kafka-headless.kafka.svc.cluster.local + ## - kafka-2.kafka-headless.kafka.svc.cluster.local + ## Note: ignored when using 'pem' format for certificates. + ## + jksKeystoreSAN: "" + ## @param auth.tls.jksTruststore The secret key from the `auth.tls.existingSecrets` or `auth.tls.jksTruststoreSecret` containing the truststore + ## Note: ignored when using 'pem' format for certificates. + ## + jksTruststore: "" + ## @param auth.tls.endpointIdentificationAlgorithm The endpoint identification algorithm to validate server hostname using server certificate + ## Disable server host name verification by setting it to an empty string. + ## ref: https://docs.confluent.io/current/kafka/authentication_ssl.html#optional-settings + ## + endpointIdentificationAlgorithm: https + ## Zookeeper client configuration for kafka brokers + ## + zookeeper: + ## TLS configuration + ## + tls: + ## @param auth.zookeeper.tls.enabled Enable TLS for Zookeeper client connections. + ## + enabled: false + ## @param auth.zookeeper.tls.type Format to use for TLS certificates. Allowed types: `jks` and `pem`. + ## + type: jks + ## @param auth.zookeeper.tls.verifyHostname Hostname validation. + ## + verifyHostname: true + ## @param auth.zookeeper.tls.existingSecret Name of the existing secret containing the TLS certificates for ZooKeeper client communications. + ## + existingSecret: "" + ## @param auth.zookeeper.tls.existingSecretKeystoreKey The secret key from the auth.zookeeper.tls.existingSecret containing the Keystore. + ## + existingSecretKeystoreKey: zookeeper.keystore.jks + ## @param auth.zookeeper.tls.existingSecretTruststoreKey The secret key from the auth.zookeeper.tls.existingSecret containing the Truststore. + ## + existingSecretTruststoreKey: zookeeper.truststore.jks + ## @param auth.zookeeper.tls.passwordsSecret Existing secret containing Keystore and Truststore passwords. + ## + passwordsSecret: "" + ## @param auth.zookeeper.tls.passwordsSecretKeystoreKey The secret key from the auth.zookeeper.tls.passwordsSecret containing the password for the Keystore. + ## + passwordsSecretKeystoreKey: keystore-password + ## @param auth.zookeeper.tls.passwordsSecretTruststoreKey The secret key from the auth.zookeeper.tls.passwordsSecret containing the password for the Truststore. + ## + passwordsSecretTruststoreKey: truststore-password +## @param listeners The address(es) the socket server listens on. Auto-calculated it's set to an empty array +## When it's set to an empty array, the listeners will be configured +## based on the authentication protocols (auth.clientProtocol, auth.externalClientProtocol and auth.interBrokerProtocol parameters) +## +listeners: [] +## @param advertisedListeners The address(es) (hostname:port) the broker will advertise to producers and consumers. Auto-calculated it's set to an empty array +## When it's set to an empty array, the advertised listeners will be configured +## based on the authentication protocols (auth.clientProtocol, auth.externalClientProtocol and auth.interBrokerProtocol parameters) +## +advertisedListeners: [] +## @param listenerSecurityProtocolMap The protocol->listener mapping. Auto-calculated it's set to nil +## When it's nil, the listeners will be configured based on the authentication protocols (auth.clientProtocol, auth.externalClientProtocol and auth.interBrokerProtocol parameters) +## +listenerSecurityProtocolMap: "" +## @param allowPlaintextListener Allow to use the PLAINTEXT listener +## +allowPlaintextListener: true +## @param interBrokerListenerName The listener that the brokers should communicate on +## +interBrokerListenerName: INTERNAL +## @param command Override Kafka container command +## +command: + - /scripts/setup.sh +## @param args Override Kafka container arguments +## +args: [] +## @param extraEnvVars Extra environment variables to add to Kafka pods +## ref: https://github.com/bitnami/containers/tree/main/bitnami/kafka#configuration +## e.g: +## extraEnvVars: +## - name: KAFKA_CFG_BACKGROUND_THREADS +## value: "10" +## +extraEnvVars: [] +## @param extraEnvVarsCM ConfigMap with extra environment variables +## +extraEnvVarsCM: "" +## @param extraEnvVarsSecret Secret with extra environment variables +## +extraEnvVarsSecret: "" + +## @section Statefulset parameters + +## @param replicaCount Number of Kafka nodes +## +replicaCount: 1 +## @param minBrokerId Minimal broker.id value, nodes increment their `broker.id` respectively +## Brokers increment their ID starting at this minimal value. +## E.g., with `minBrokerId=100` and 3 nodes, IDs will be 100, 101, 102 for brokers 0, 1, and 2, respectively. +## +minBrokerId: 0 +## @param brokerRackAssignment Set Broker Assignment for multi tenant environment Allowed values: `aws-az` +## ref: https://cwiki.apache.org/confluence/display/KAFKA/KIP-392%3A+Allow+consumers+to+fetch+from+closest+replica +## +brokerRackAssignment: "" +## @param containerPorts.client Kafka client container port +## @param containerPorts.internal Kafka inter-broker container port +## @param containerPorts.external Kafka external container port +## +containerPorts: + client: 9092 + internal: 9093 + external: 9094 +## Configure extra options for Kafka containers' liveness, readiness and startup probes +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes +## @param livenessProbe.enabled Enable livenessProbe on Kafka containers +## @param livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe +## @param livenessProbe.periodSeconds Period seconds for livenessProbe +## @param livenessProbe.timeoutSeconds Timeout seconds for livenessProbe +## @param livenessProbe.failureThreshold Failure threshold for livenessProbe +## @param livenessProbe.successThreshold Success threshold for livenessProbe +## +livenessProbe: + enabled: true + initialDelaySeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + periodSeconds: 10 + successThreshold: 1 +## @param readinessProbe.enabled Enable readinessProbe on Kafka containers +## @param readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe +## @param readinessProbe.periodSeconds Period seconds for readinessProbe +## @param readinessProbe.timeoutSeconds Timeout seconds for readinessProbe +## @param readinessProbe.failureThreshold Failure threshold for readinessProbe +## @param readinessProbe.successThreshold Success threshold for readinessProbe +## +readinessProbe: + enabled: true + initialDelaySeconds: 5 + failureThreshold: 6 + timeoutSeconds: 5 + periodSeconds: 10 + successThreshold: 1 +## @param startupProbe.enabled Enable startupProbe on Kafka containers +## @param startupProbe.initialDelaySeconds Initial delay seconds for startupProbe +## @param startupProbe.periodSeconds Period seconds for startupProbe +## @param startupProbe.timeoutSeconds Timeout seconds for startupProbe +## @param startupProbe.failureThreshold Failure threshold for startupProbe +## @param startupProbe.successThreshold Success threshold for startupProbe +## +startupProbe: + enabled: false + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 15 + successThreshold: 1 +## @param customLivenessProbe Custom livenessProbe that overrides the default one +## +customLivenessProbe: {} +## @param customReadinessProbe Custom readinessProbe that overrides the default one +## +customReadinessProbe: {} +## @param customStartupProbe Custom startupProbe that overrides the default one +## +customStartupProbe: {} +## @param lifecycleHooks lifecycleHooks for the Kafka container to automate configuration before or after startup +## +lifecycleHooks: {} +## Kafka resource requests and limits +## ref: https://kubernetes.io/docs/user-guide/compute-resources/ +## @param resources.limits The resources limits for the container +## @param resources.requests The requested resources for the container +## +resources: + limits: {} + requests: {} +## Kafka pods' Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod +## @param podSecurityContext.enabled Enable security context for the pods +## @param podSecurityContext.fsGroup Set Kafka pod's Security Context fsGroup +## +podSecurityContext: + enabled: true + fsGroup: 1001 +## Kafka containers' Security Context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container +## @param containerSecurityContext.enabled Enable Kafka containers' Security Context +## @param containerSecurityContext.runAsUser Set Kafka containers' Security Context runAsUser +## @param containerSecurityContext.runAsNonRoot Set Kafka containers' Security Context runAsNonRoot +## @param containerSecurityContext.allowPrivilegeEscalation Force the child process to be run as nonprivilege +## e.g: +## containerSecurityContext: +## enabled: true +## capabilities: +## drop: ["NET_RAW"] +## readOnlyRootFilesystem: true +## +containerSecurityContext: + enabled: true + runAsUser: 1001 + runAsNonRoot: true + allowPrivilegeEscalation: false +## @param hostAliases Kafka pods host aliases +## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ +## +hostAliases: [] +## @param hostNetwork Specify if host network should be enabled for Kafka pods +## +hostNetwork: false +## @param hostIPC Specify if host IPC should be enabled for Kafka pods +## +hostIPC: false +## @param podLabels Extra labels for Kafka pods +## Ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ +## +podLabels: {} +## @param podAnnotations Extra annotations for Kafka pods +## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ +## +podAnnotations: {} +## @param podAffinityPreset Pod affinity preset. Ignored if `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 podAntiAffinityPreset Pod anti-affinity preset. Ignored if `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 +## Node affinity preset +## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity +## +nodeAffinityPreset: + ## @param nodeAffinityPreset.type Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` + ## + type: "" + ## @param nodeAffinityPreset.key Node label key to match Ignored if `affinity` is set. + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## @param nodeAffinityPreset.values Node label values to match. Ignored if `affinity` is set. + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] +## @param affinity Affinity for pod 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 nodeSelector Node labels for pod assignment +## Ref: https://kubernetes.io/docs/user-guide/node-selection/ +## +nodeSelector: {} +## @param tolerations Tolerations for pod assignment +## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ +## +tolerations: [] +## @param topologySpreadConstraints Topology Spread Constraints for pod assignment spread across your cluster among failure-domains. Evaluated as a template +## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#spread-constraints-for-pods +## +topologySpreadConstraints: [] +## @param terminationGracePeriodSeconds Seconds the pod needs to gracefully terminate +## ref: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#hook-handler-execution +## +terminationGracePeriodSeconds: "" +## @param podManagementPolicy StatefulSet controller supports relax its ordering guarantees while preserving its uniqueness and identity guarantees. There are two valid pod management policies: OrderedReady and Parallel +## ref: https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/#pod-management-policy +## +podManagementPolicy: Parallel +## @param priorityClassName Name of the existing priority class to be used by kafka pods +## Ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ +## +priorityClassName: "" +## @param schedulerName Name of the k8s scheduler (other than default) +## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ +## +schedulerName: "" +## @param updateStrategy.type Kafka statefulset strategy type +## @param updateStrategy.rollingUpdate Kafka statefulset rolling update configuration parameters +## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies +## +updateStrategy: + type: RollingUpdate + rollingUpdate: {} +## @param extraVolumes Optionally specify extra list of additional volumes for the Kafka pod(s) +## e.g: +## extraVolumes: +## - name: kafka-jaas +## secret: +## secretName: kafka-jaas +## +extraVolumes: [] +## @param extraVolumeMounts Optionally specify extra list of additional volumeMounts for the Kafka container(s) +## extraVolumeMounts: +## - name: kafka-jaas +## mountPath: /bitnami/kafka/config/kafka_jaas.conf +## subPath: kafka_jaas.conf +## +extraVolumeMounts: [] +## @param sidecars Add additional sidecar containers to the Kafka pod(s) +## e.g: +## sidecars: +## - name: your-image-name +## image: your-image +## imagePullPolicy: Always +## ports: +## - name: portname +## containerPort: 1234 +## +sidecars: [] +## @param initContainers Add additional Add init containers to the Kafka pod(s) +## e.g: +## initContainers: +## - name: your-image-name +## image: your-image +## imagePullPolicy: Always +## ports: +## - name: portname +## containerPort: 1234 +## +initContainers: [] +## Kafka Pod Disruption Budget +## ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ +## @param pdb.create Deploy a pdb object for the Kafka pod +## @param pdb.minAvailable Maximum number/percentage of unavailable Kafka replicas +## @param pdb.maxUnavailable Maximum number/percentage of unavailable Kafka replicas +## +pdb: + create: false + minAvailable: "" + maxUnavailable: 1 + +## @section Traffic Exposure parameters + +## Service parameters +## +service: + ## @param service.type Kubernetes Service type + ## + type: ClusterIP + ## @param service.ports.client Kafka svc port for client connections + ## @param service.ports.internal Kafka svc port for inter-broker connections + ## @param service.ports.external Kafka svc port for external connections + ## + ports: + client: 9092 + internal: 9093 + external: 9094 + ## @param service.nodePorts.client Node port for the Kafka client connections + ## @param service.nodePorts.external Node port for the Kafka external connections + ## NOTE: choose port between <30000-32767> + ## + nodePorts: + client: "" + external: "" + ## @param service.sessionAffinity Control where client requests go, to the same pod or round-robin + ## Values: ClientIP or None + ## ref: https://kubernetes.io/docs/user-guide/services/ + ## + sessionAffinity: None + ## @param service.sessionAffinityConfig Additional settings for the sessionAffinity + ## sessionAffinityConfig: + ## clientIP: + ## timeoutSeconds: 300 + ## + sessionAffinityConfig: {} + ## @param service.clusterIP Kafka service Cluster IP + ## e.g.: + ## clusterIP: None + ## + clusterIP: "" + ## @param service.loadBalancerIP Kafka service Load Balancer IP + ## ref: https://kubernetes.io/docs/user-guide/services/#type-loadbalancer + ## + loadBalancerIP: "" + ## @param service.loadBalancerSourceRanges Kafka service Load Balancer sources + ## ref: 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 service.externalTrafficPolicy Kafka service external traffic policy + ## ref https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + ## + externalTrafficPolicy: Cluster + ## @param service.annotations Additional custom annotations for Kafka service + ## + annotations: {} + ## Headless service properties + ## + headless: + ## @param service.headless.publishNotReadyAddresses Indicates that any agent which deals with endpoints for this Service should disregard any indications of ready/not-ready + ## ref: https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/ + publishNotReadyAddresses: false + ## @param service.headless.annotations Annotations for the headless service. + ## + annotations: {} + ## @param service.headless.labels Labels for the headless service. + ## + labels: {} + ## @param service.extraPorts Extra ports to expose in the Kafka service (normally used with the `sidecar` value) + ## + extraPorts: [] +## External Access to Kafka brokers configuration +## +externalAccess: + ## @param externalAccess.enabled Enable Kubernetes external cluster access to Kafka brokers + ## + enabled: false + ## External IPs auto-discovery configuration + ## An init container is used to auto-detect LB IPs or node ports by querying the K8s API + ## Note: RBAC might be required + ## + autoDiscovery: + ## @param externalAccess.autoDiscovery.enabled Enable using an init container to auto-detect external IPs/ports by querying the K8s API + ## + enabled: false + ## Bitnami Kubectl image + ## ref: https://hub.docker.com/r/bitnami/kubectl/tags/ + ## @param externalAccess.autoDiscovery.image.registry Init container auto-discovery image registry + ## @param externalAccess.autoDiscovery.image.repository Init container auto-discovery image repository + ## @param externalAccess.autoDiscovery.image.tag Init container auto-discovery image tag (immutable tags are recommended) + ## @param externalAccess.autoDiscovery.image.digest Petete image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag + ## @param externalAccess.autoDiscovery.image.pullPolicy Init container auto-discovery image pull policy + ## @param externalAccess.autoDiscovery.image.pullSecrets Init container auto-discovery image pull secrets + ## + image: + registry: docker.io + repository: bitnami/kubectl + tag: 1.25.5-debian-11-r2 + 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/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## Init Container resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## @param externalAccess.autoDiscovery.resources.limits The resources limits for the auto-discovery init container + ## @param externalAccess.autoDiscovery.resources.requests The requested resources for the auto-discovery init container + ## + resources: + limits: {} + requests: {} + ## Parameters to configure K8s service(s) used to externally access Kafka brokers + ## Note: A new service per broker will be created + ## + service: + ## @param externalAccess.service.type Kubernetes Service type for external access. It can be NodePort, LoadBalancer or ClusterIP + ## + type: LoadBalancer + ## @param externalAccess.service.ports.external Kafka port used for external access when service type is LoadBalancer + ## + ports: + external: 9094 + ## @param externalAccess.service.loadBalancerIPs Array of load balancer IPs for each Kafka broker. Length must be the same as replicaCount + ## e.g: + ## loadBalancerIPs: + ## - X.X.X.X + ## - Y.Y.Y.Y + ## + loadBalancerIPs: [] + ## @param externalAccess.service.loadBalancerNames Array of load balancer Names for each Kafka broker. Length must be the same as replicaCount + ## e.g: + ## loadBalancerNames: + ## - broker1.external.example.com + ## - broker2.external.example.com + ## + loadBalancerNames: [] + ## @param externalAccess.service.loadBalancerAnnotations Array of load balancer annotations for each Kafka broker. Length must be the same as replicaCount + ## e.g: + ## loadBalancerAnnotations: + ## - external-dns.alpha.kubernetes.io/hostname: broker1.external.example.com. + ## - external-dns.alpha.kubernetes.io/hostname: broker2.external.example.com. + ## + loadBalancerAnnotations: [] + ## @param externalAccess.service.loadBalancerSourceRanges Address(es) that are allowed when service is LoadBalancer + ## ref: 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 externalAccess.service.nodePorts Array of node ports used for each Kafka broker. Length must be the same as replicaCount + ## e.g: + ## nodePorts: + ## - 30001 + ## - 30002 + ## + nodePorts: [] + ## @param externalAccess.service.useHostIPs Use service host IPs to configure Kafka external listener when service type is NodePort + ## + useHostIPs: false + ## @param externalAccess.service.usePodIPs using the MY_POD_IP address for external access. + ## + usePodIPs: false + ## @param externalAccess.service.domain Domain or external ip used to configure Kafka external listener when service type is NodePort or ClusterIP + ## NodePort: If not specified, the container will try to get the kubernetes node external IP + ## ClusterIP: Must be specified, ingress IP or domain where tcp for external ports is configured + ## + domain: "" + ## @param externalAccess.service.publishNotReadyAddresses Indicates that any agent which deals with endpoints for this Service should disregard any indications of ready/not-ready + ## ref: https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/ + publishNotReadyAddresses: false + ## @param externalAccess.service.labels Service labels for external access + ## + labels: {} + ## @param externalAccess.service.annotations Service annotations for external access + ## + annotations: {} + ## @param externalAccess.service.extraPorts Extra ports to expose in the Kafka external service + ## + extraPorts: [] +## Network policies +## Ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ +## +networkPolicy: + ## @param networkPolicy.enabled Specifies whether a NetworkPolicy should be created + ## + enabled: false + ## @param networkPolicy.allowExternal Don't require client label for connections + ## When set to false, only pods with the correct client label will have network access to the port Kafka is + ## listening on. When true, zookeeper accept connections from any source (with the correct destination port). + ## + allowExternal: true + ## @param networkPolicy.explicitNamespacesSelector A Kubernetes LabelSelector to explicitly select namespaces from which traffic could be allowed + ## If explicitNamespacesSelector is missing or set to {}, only client Pods that are in the networkPolicy's namespace + ## and that match other criteria, the ones that have the good label, can reach the kafka. + ## But sometimes, we want the kafka to be accessible to clients from other namespaces, in this case, we can use this + ## LabelSelector to select these namespaces, note that the networkPolicy's namespace should also be explicitly added. + ## + ## e.g: + ## explicitNamespacesSelector: + ## matchLabels: + ## role: frontend + ## matchExpressions: + ## - {key: role, operator: In, values: [frontend]} + ## + explicitNamespacesSelector: {} + ## @param networkPolicy.externalAccess.from customize the from section for External Access on tcp-external port + ## e.g: + ## - ipBlock: + ## cidr: 172.9.0.0/16 + ## except: + ## - 172.9.1.0/24 + ## + externalAccess: + from: [] + ## @param networkPolicy.egressRules.customRules [object] Custom network policy rule + ## + egressRules: + ## Additional custom egress rules + ## e.g: + ## customRules: + ## - to: + ## - namespaceSelector: + ## matchLabels: + ## label: example + customRules: [] + +## @section Persistence parameters + +## Enable persistence using Persistent Volume Claims +## ref: https://kubernetes.io/docs/user-guide/persistent-volumes/ +## +persistence: + ## @param persistence.enabled Enable Kafka data persistence using PVC, note that ZooKeeper persistence is unaffected + ## + enabled: true + ## @param persistence.existingClaim A manually managed Persistent Volume and Claim + ## If defined, PVC must be created manually before volume will be bound + ## The value is evaluated as a template + ## + existingClaim: "" + ## @param persistence.storageClass PVC Storage Class for Kafka data volume + ## 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. + ## + storageClass: "" + ## @param persistence.accessModes Persistent Volume Access Modes + ## + accessModes: + - ReadWriteOnce + ## @param persistence.size PVC Storage Request for Kafka data volume + ## + size: 8Gi + ## @param persistence.annotations Annotations for the PVC + ## + annotations: {} + ## @param persistence.labels Labels for the PVC + ## + labels: {} + ## @param persistence.selector Selector to match an existing Persistent Volume for Kafka data PVC. If set, the PVC can't have a PV dynamically provisioned for it + ## selector: + ## matchLabels: + ## app: my-app + ## + selector: {} + ## @param persistence.mountPath Mount path of the Kafka data volume + ## + mountPath: /bitnami/kafka +## Log Persistence parameters +## +logPersistence: + ## @param logPersistence.enabled Enable Kafka logs persistence using PVC, note that ZooKeeper persistence is unaffected + ## + enabled: false + ## @param logPersistence.existingClaim A manually managed Persistent Volume and Claim + ## If defined, PVC must be created manually before volume will be bound + ## The value is evaluated as a template + ## + existingClaim: "" + ## @param logPersistence.storageClass PVC Storage Class for Kafka logs volume + ## 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. + ## + storageClass: "" + ## @param logPersistence.accessModes Persistent Volume Access Modes + ## + accessModes: + - ReadWriteOnce + ## @param logPersistence.size PVC Storage Request for Kafka logs volume + ## + size: 8Gi + ## @param logPersistence.annotations Annotations for the PVC + ## + annotations: {} + ## @param logPersistence.selector Selector to match an existing Persistent Volume for Kafka log data PVC. If set, the PVC can't have a PV dynamically provisioned for it + ## selector: + ## matchLabels: + ## app: my-app + ## + selector: {} + ## @param logPersistence.mountPath Mount path of the Kafka logs volume + ## + mountPath: /opt/bitnami/kafka/logs + +## @section Volume Permissions parameters +## + +## Init containers parameters: +## volumePermissions: Change the owner and group of the persistent volume(s) mountpoint(s) to 'runAsUser:fsGroup' on each node +## +volumePermissions: + ## @param volumePermissions.enabled Enable init container that changes the owner and group of the persistent volume + ## + 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 Init container volume-permissions image pull secrets + ## + image: + registry: docker.io + repository: bitnami/bitnami-shell + tag: 11-debian-11-r63 + 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: [] + ## Init container resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## @param volumePermissions.resources.limits Init container volume-permissions resource limits + ## @param volumePermissions.resources.requests Init container volume-permissions resource requests + ## + resources: + limits: {} + requests: {} + ## Init container' Security Context + ## Note: the chown of the data folder is done to containerSecurityContext.runAsUser + ## and not the below volumePermissions.containerSecurityContext.runAsUser + ## @param volumePermissions.containerSecurityContext.runAsUser User ID for the init container + ## + containerSecurityContext: + runAsUser: 0 + +## @section Other Parameters + +## ServiceAccount for Kafka +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +## +serviceAccount: + ## @param serviceAccount.create Enable creation of ServiceAccount for Kafka pods + ## + create: true + ## @param serviceAccount.name The name of the service account to use. If not set and `create` is `true`, a name is generated + ## If not set and create is true, a name is generated using the kafka.serviceAccountName template + ## + name: "" + ## @param serviceAccount.automountServiceAccountToken Allows auto mount of ServiceAccountToken on the serviceAccount created + ## Can be set to false if pods using this serviceAccount do not need to use K8s API + ## + automountServiceAccountToken: true + ## @param serviceAccount.annotations Additional custom annotations for the ServiceAccount + ## + annotations: {} +## Role Based Access Control +## ref: https://kubernetes.io/docs/admin/authorization/rbac/ +## +rbac: + ## @param rbac.create Whether to create & use RBAC resources or not + ## binding Kafka ServiceAccount to a role + ## that allows Kafka pods querying the K8s API + ## + create: false + +## @section Metrics parameters + +## Prometheus Exporters / Metrics +## +metrics: + ## Prometheus Kafka exporter: exposes complimentary metrics to JMX exporter + ## + kafka: + ## @param metrics.kafka.enabled Whether or not to create a standalone Kafka exporter to expose Kafka metrics + ## + enabled: false + ## Bitnami Kafka exporter image + ## ref: https://hub.docker.com/r/bitnami/kafka-exporter/tags/ + ## @param metrics.kafka.image.registry Kafka exporter image registry + ## @param metrics.kafka.image.repository Kafka exporter image repository + ## @param metrics.kafka.image.tag Kafka exporter image tag (immutable tags are recommended) + ## @param metrics.kafka.image.digest Kafka exporter image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag + ## @param metrics.kafka.image.pullPolicy Kafka exporter image pull policy + ## @param metrics.kafka.image.pullSecrets Specify docker-registry secret names as an array + ## + image: + registry: docker.io + repository: bitnami/kafka-exporter + tag: 1.6.0-debian-11-r40 + 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/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + + ## @param metrics.kafka.certificatesSecret Name of the existing secret containing the optional certificate and key files + ## for Kafka exporter client authentication + ## + certificatesSecret: "" + ## @param metrics.kafka.tlsCert The secret key from the certificatesSecret if 'client-cert' key different from the default (cert-file) + ## + tlsCert: cert-file + ## @param metrics.kafka.tlsKey The secret key from the certificatesSecret if 'client-key' key different from the default (key-file) + ## + tlsKey: key-file + ## @param metrics.kafka.tlsCaSecret Name of the existing secret containing the optional ca certificate for Kafka exporter client authentication + ## + tlsCaSecret: "" + ## @param metrics.kafka.tlsCaCert The secret key from the certificatesSecret or tlsCaSecret if 'ca-cert' key different from the default (ca-file) + ## + tlsCaCert: ca-file + ## @param metrics.kafka.extraFlags Extra flags to be passed to Kafka exporter + ## e.g: + ## extraFlags: + ## tls.insecure-skip-tls-verify: "" + ## web.telemetry-path: "/metrics" + ## + extraFlags: {} + ## @param metrics.kafka.command Override Kafka exporter container command + ## + command: [] + ## @param metrics.kafka.args Override Kafka exporter container arguments + ## + args: [] + ## @param metrics.kafka.containerPorts.metrics Kafka exporter metrics container port + ## + containerPorts: + metrics: 9308 + ## Kafka exporter resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## @param metrics.kafka.resources.limits The resources limits for the container + ## @param metrics.kafka.resources.requests The requested resources for the container + ## + resources: + limits: {} + requests: {} + ## Kafka exporter pods' Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod + ## @param metrics.kafka.podSecurityContext.enabled Enable security context for the pods + ## @param metrics.kafka.podSecurityContext.fsGroup Set Kafka exporter pod's Security Context fsGroup + ## + podSecurityContext: + enabled: true + fsGroup: 1001 + ## Kafka exporter containers' Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + ## @param metrics.kafka.containerSecurityContext.enabled Enable Kafka exporter containers' Security Context + ## @param metrics.kafka.containerSecurityContext.runAsUser Set Kafka exporter containers' Security Context runAsUser + ## @param metrics.kafka.containerSecurityContext.runAsNonRoot Set Kafka exporter containers' Security Context runAsNonRoot + ## e.g: + ## containerSecurityContext: + ## enabled: true + ## capabilities: + ## drop: ["NET_RAW"] + ## readOnlyRootFilesystem: true + ## + containerSecurityContext: + enabled: true + runAsUser: 1001 + runAsNonRoot: true + ## @param metrics.kafka.hostAliases Kafka exporter pods host aliases + ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ + ## + hostAliases: [] + ## @param metrics.kafka.podLabels Extra labels for Kafka exporter pods + ## Ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + ## + podLabels: {} + ## @param metrics.kafka.podAnnotations Extra annotations for Kafka exporter pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + podAnnotations: {} + ## @param metrics.kafka.podAffinityPreset Pod affinity preset. Ignored if `metrics.kafka.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 metrics.kafka.podAntiAffinityPreset Pod anti-affinity preset. Ignored if `metrics.kafka.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 + ## Node metrics.kafka.affinity preset + ## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## + nodeAffinityPreset: + ## @param metrics.kafka.nodeAffinityPreset.type Node affinity preset type. Ignored if `metrics.kafka.affinity` is set. Allowed values: `soft` or `hard` + ## + type: "" + ## @param metrics.kafka.nodeAffinityPreset.key Node label key to match Ignored if `metrics.kafka.affinity` is set. + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## @param metrics.kafka.nodeAffinityPreset.values Node label values to match. Ignored if `metrics.kafka.affinity` is set. + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + ## @param metrics.kafka.affinity Affinity for pod assignment + ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: metrics.kafka.podAffinityPreset, metrics.kafka.podAntiAffinityPreset, and metrics.kafka.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + ## @param metrics.kafka.nodeSelector Node labels for pod assignment + ## Ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + ## @param metrics.kafka.tolerations Tolerations for pod assignment + ## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + ## @param metrics.kafka.schedulerName Name of the k8s scheduler (other than default) for Kafka exporter + ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ + ## + schedulerName: "" + ## @param metrics.kafka.priorityClassName Kafka exporter pods' priorityClassName + ## + priorityClassName: "" + ## @param metrics.kafka.topologySpreadConstraints Topology Spread Constraints for pod assignment + ## https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ + ## The value is evaluated as a template + ## + topologySpreadConstraints: [] + ## @param metrics.kafka.extraVolumes Optionally specify extra list of additional volumes for the Kafka exporter pod(s) + ## e.g: + ## extraVolumes: + ## - name: kafka-jaas + ## secret: + ## secretName: kafka-jaas + ## + extraVolumes: [] + ## @param metrics.kafka.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the Kafka exporter container(s) + ## extraVolumeMounts: + ## - name: kafka-jaas + ## mountPath: /bitnami/kafka/config/kafka_jaas.conf + ## subPath: kafka_jaas.conf + ## + extraVolumeMounts: [] + ## @param metrics.kafka.sidecars Add additional sidecar containers to the Kafka exporter pod(s) + ## e.g: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + ## @param metrics.kafka.initContainers Add init containers to the Kafka exporter pods + ## e.g: + ## initContainers: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + initContainers: [] + ## Kafka exporter service configuration + ## + service: + ## @param metrics.kafka.service.ports.metrics Kafka exporter metrics service port + ## + ports: + metrics: 9308 + ## @param metrics.kafka.service.clusterIP Static clusterIP or None for headless services + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#choosing-your-own-ip-address + ## + clusterIP: "" + ## @param metrics.kafka.service.sessionAffinity Control where client requests go, to the same pod or round-robin + ## Values: ClientIP or None + ## ref: https://kubernetes.io/docs/user-guide/services/ + ## + sessionAffinity: None + ## @param metrics.kafka.service.annotations [object] Annotations for the Kafka exporter service + ## + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "{{ .Values.metrics.kafka.service.ports.metrics }}" + prometheus.io/path: "/metrics" + ## Kafka exporter pods ServiceAccount + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ + ## + serviceAccount: + ## @param metrics.kafka.serviceAccount.create Enable creation of ServiceAccount for Kafka exporter pods + ## + create: true + ## @param metrics.kafka.serviceAccount.name The name of the service account to use. If not set and `create` is `true`, a name is generated + ## If not set and create is true, a name is generated using the kafka.metrics.kafka.serviceAccountName template + ## + name: "" + ## @param metrics.kafka.serviceAccount.automountServiceAccountToken Allows auto mount of ServiceAccountToken on the serviceAccount created + ## Can be set to false if pods using this serviceAccount do not need to use K8s API + ## + automountServiceAccountToken: true + ## Prometheus JMX exporter: exposes the majority of Kafkas metrics + ## + jmx: + ## @param metrics.jmx.enabled Whether or not to expose JMX metrics to Prometheus + ## + enabled: false + ## Bitnami JMX exporter image + ## ref: https://hub.docker.com/r/bitnami/jmx-exporter/tags/ + ## @param metrics.jmx.image.registry JMX exporter image registry + ## @param metrics.jmx.image.repository JMX exporter image repository + ## @param metrics.jmx.image.tag JMX exporter image tag (immutable tags are recommended) + ## @param metrics.jmx.image.digest JMX exporter image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag + ## @param metrics.jmx.image.pullPolicy JMX exporter image pull policy + ## @param metrics.jmx.image.pullSecrets Specify docker-registry secret names as an array + ## + image: + registry: docker.io + repository: bitnami/jmx-exporter + tag: 0.17.2-debian-11-r29 + 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/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## Prometheus JMX exporter containers' Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + ## @param metrics.jmx.containerSecurityContext.enabled Enable Prometheus JMX exporter containers' Security Context + ## @param metrics.jmx.containerSecurityContext.runAsUser Set Prometheus JMX exporter containers' Security Context runAsUser + ## @param metrics.jmx.containerSecurityContext.runAsNonRoot Set Prometheus JMX exporter containers' Security Context runAsNonRoot + ## e.g: + ## containerSecurityContext: + ## enabled: true + ## capabilities: + ## drop: ["NET_RAW"] + ## readOnlyRootFilesystem: true + ## + containerSecurityContext: + enabled: true + runAsUser: 1001 + runAsNonRoot: true + ## @param metrics.jmx.containerPorts.metrics Prometheus JMX exporter metrics container port + ## + containerPorts: + metrics: 5556 + ## Prometheus JMX exporter resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## @param metrics.jmx.resources.limits The resources limits for the JMX exporter container + ## @param metrics.jmx.resources.requests The requested resources for the JMX exporter container + ## + resources: + limits: {} + requests: {} + ## Prometheus JMX exporter service configuration + ## + service: + ## @param metrics.jmx.service.ports.metrics Prometheus JMX exporter metrics service port + ## + ports: + metrics: 5556 + ## @param metrics.jmx.service.clusterIP Static clusterIP or None for headless services + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#choosing-your-own-ip-address + ## + clusterIP: "" + ## @param metrics.jmx.service.sessionAffinity Control where client requests go, to the same pod or round-robin + ## Values: ClientIP or None + ## ref: https://kubernetes.io/docs/user-guide/services/ + ## + sessionAffinity: None + ## @param metrics.jmx.service.annotations [object] Annotations for the Prometheus JMX exporter service + ## + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "{{ .Values.metrics.jmx.service.ports.metrics }}" + prometheus.io/path: "/" + ## @param metrics.jmx.whitelistObjectNames Allows setting which JMX objects you want to expose to via JMX stats to JMX exporter + ## Only whitelisted values will be exposed via JMX exporter. They must also be exposed via Rules. To expose all metrics + ## (warning its crazy excessive and they aren't formatted in a prometheus style) (1) `whitelistObjectNames: []` + ## (2) commented out above `overrideConfig`. + ## + whitelistObjectNames: + - kafka.controller:* + - kafka.server:* + - java.lang:* + - kafka.network:* + - kafka.log:* + ## @param metrics.jmx.config [string] Configuration file for JMX exporter + ## Specify content for jmx-kafka-prometheus.yml. Evaluated as a template + ## + ## Credits to the incubator/kafka chart for the JMX configuration. + ## https://github.com/helm/charts/tree/master/incubator/kafka + ## + config: |- + jmxUrl: service:jmx:rmi:///jndi/rmi://127.0.0.1:5555/jmxrmi + lowercaseOutputName: true + lowercaseOutputLabelNames: true + ssl: false + {{- if .Values.metrics.jmx.whitelistObjectNames }} + whitelistObjectNames: ["{{ join "\",\"" .Values.metrics.jmx.whitelistObjectNames }}"] + {{- end }} + ## @param metrics.jmx.existingConfigmap Name of existing ConfigMap with JMX exporter configuration + ## NOTE: This will override metrics.jmx.config + ## + existingConfigmap: "" + ## @param metrics.jmx.extraRules Add extra rules to JMX exporter configuration + ## e.g: + ## extraRules: |- + ## - pattern: kafka.server<>(connection-count) + ## name: kafka_server_socket_server_metrics_$3 + ## labels: + ## listener: $1 + extraRules: "" + ## Prometheus Operator ServiceMonitor configuration + ## + serviceMonitor: + ## @param metrics.serviceMonitor.enabled if `true`, creates a Prometheus Operator ServiceMonitor (requires `metrics.kafka.enabled` or `metrics.jmx.enabled` to be `true`) + ## + enabled: false + ## @param metrics.serviceMonitor.namespace Namespace in which Prometheus is running + ## + namespace: "" + ## @param metrics.serviceMonitor.interval Interval at which metrics should be scraped + ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#endpoint + ## + interval: "" + ## @param metrics.serviceMonitor.scrapeTimeout Timeout after which the scrape is ended + ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#endpoint + ## + scrapeTimeout: "" + ## @param metrics.serviceMonitor.labels Additional labels that can be used so ServiceMonitor will be discovered by Prometheus + ## + labels: {} + ## @param metrics.serviceMonitor.selector Prometheus instance selector labels + ## ref: https://github.com/bitnami/charts/tree/main/bitnami/prometheus-operator#prometheus-configuration + ## + selector: {} + ## @param metrics.serviceMonitor.relabelings RelabelConfigs to apply to samples before scraping + ## + relabelings: [] + ## @param metrics.serviceMonitor.metricRelabelings MetricRelabelConfigs to apply to samples before ingestion + ## + metricRelabelings: [] + ## @param metrics.serviceMonitor.honorLabels Specify honorLabels parameter to add the scrape endpoint + ## + honorLabels: false + ## @param metrics.serviceMonitor.jobLabel The name of the label on the target service to use as the job name in prometheus. + ## + jobLabel: "" + + prometheusRule: + ## @param metrics.prometheusRule.enabled if `true`, creates a Prometheus Operator PrometheusRule (requires `metrics.kafka.enabled` or `metrics.jmx.enabled` to be `true`) + ## + enabled: false + ## @param metrics.prometheusRule.namespace Namespace in which Prometheus is running + ## + namespace: "" + ## @param metrics.prometheusRule.labels Additional labels that can be used so PrometheusRule will be discovered by Prometheus + ## + labels: {} + ## @param metrics.prometheusRule.groups Prometheus Rule Groups for Kafka + ## + groups: [] + +## @section Kafka provisioning parameters + +## Kafka provisioning +## +provisioning: + ## @param provisioning.enabled Enable kafka provisioning Job + ## + enabled: false + ## @param provisioning.numPartitions Default number of partitions for topics when unspecified + ## + numPartitions: 1 + ## @param provisioning.replicationFactor Default replication factor for topics when unspecified + ## + replicationFactor: 1 + ## @param provisioning.topics Kafka topics to provision + ## - name: topic-name + ## partitions: 1 + ## replicationFactor: 1 + ## ## https://kafka.apache.org/documentation/#topicconfigs + ## config: + ## max.message.bytes: 64000 + ## flush.messages: 1 + ## + topics: [] + ## @param provisioning.nodeSelector Node labels for pod assignment + ## Ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + ## @param provisioning.tolerations Tolerations for pod assignment + ## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + ## @param provisioning.extraProvisioningCommands Extra commands to run to provision cluster resources + ## - echo "Allow user to consume from any topic" + ## - >- + ## /opt/bitnami/kafka/bin/kafka-acls.sh + ## --bootstrap-server $KAFKA_SERVICE + ## --command-config $CLIENT_CONF + ## --add + ## --allow-principal User:user + ## --consumer --topic '*' + ## - "/opt/bitnami/kafka/bin/kafka-acls.sh + ## --bootstrap-server $KAFKA_SERVICE + ## --command-config $CLIENT_CONF + ## --list" + ## + extraProvisioningCommands: [] + ## @param provisioning.parallel Number of provisioning commands to run at the same time + ## + parallel: 1 + ## @param provisioning.preScript Extra bash script to run before topic provisioning. $CLIENT_CONF is path to properties file with most needed configurations + ## + preScript: "" + ## @param provisioning.postScript Extra bash script to run after topic provisioning. $CLIENT_CONF is path to properties file with most needed configurations + ## + postScript: "" + ## Auth Configuration for kafka provisioning Job + ## + auth: + ## TLS configuration for kafka provisioning Job + ## + tls: + ## @param provisioning.auth.tls.type Format to use for TLS certificates. Allowed types: `jks` and `pem`. + ## Note: ignored if auth.tls.clientProtocol different from one of these values: "tls" "mtls" "sasl_tls". + ## + type: jks + ## @param provisioning.auth.tls.certificatesSecret Existing secret containing the TLS certificates for the Kafka provisioning Job. + ## When using 'jks' format for certificates, the secret should contain a truststore and a keystore. + ## When using 'pem' format for certificates, the secret should contain a public CA certificate, a public certificate and one private key. + ## + certificatesSecret: "" + ## @param provisioning.auth.tls.cert The secret key from the certificatesSecret if 'cert' key different from the default (tls.crt) + ## + cert: tls.crt + ## @param provisioning.auth.tls.key The secret key from the certificatesSecret if 'key' key different from the default (tls.key) + ## + key: tls.key + ## @param provisioning.auth.tls.caCert The secret key from the certificatesSecret if 'caCert' key different from the default (ca.crt) + ## + caCert: ca.crt + ## @param provisioning.auth.tls.keystore The secret key from the certificatesSecret if 'keystore' key different from the default (keystore.jks) + ## + keystore: keystore.jks + ## @param provisioning.auth.tls.truststore The secret key from the certificatesSecret if 'truststore' key different from the default (truststore.jks) + ## + truststore: truststore.jks + ## @param provisioning.auth.tls.passwordsSecret Name of the secret containing passwords to access the JKS files or PEM key when they are password-protected. + ## It should contain two keys called "keystore-password" and "truststore-password", or "key-password" if using a password-protected PEM key. + ## + passwordsSecret: "" + ## @param provisioning.auth.tls.keyPasswordSecretKey The secret key from the passwordsSecret if 'keyPasswordSecretKey' key different from the default (key-password) + ## Note: must not be used if `passwordsSecret` is not defined. + ## + keyPasswordSecretKey: key-password + ## @param provisioning.auth.tls.keystorePasswordSecretKey The secret key from the passwordsSecret if 'keystorePasswordSecretKey' key different from the default (keystore-password) + ## Note: must not be used if `passwordsSecret` is not defined. + ## + keystorePasswordSecretKey: keystore-password + ## @param provisioning.auth.tls.truststorePasswordSecretKey The secret key from the passwordsSecret if 'truststorePasswordSecretKey' key different from the default (truststore-password) + ## Note: must not be used if `passwordsSecret` is not defined. + ## + truststorePasswordSecretKey: truststore-password + ## @param provisioning.auth.tls.keyPassword Password to access the password-protected PEM key if necessary. Ignored if 'passwordsSecret' is provided. + ## + keyPassword: "" + ## @param provisioning.auth.tls.keystorePassword Password to access the JKS keystore. Ignored if 'passwordsSecret' is provided. + ## + keystorePassword: "" + ## @param provisioning.auth.tls.truststorePassword Password to access the JKS truststore. Ignored if 'passwordsSecret' is provided. + ## + truststorePassword: "" + ## @param provisioning.command Override provisioning container command + ## + command: [] + ## @param provisioning.args Override provisioning container arguments + ## + args: [] + ## @param provisioning.extraEnvVars Extra environment variables to add to the provisioning pod + ## e.g: + ## extraEnvVars: + ## - name: KAFKA_CFG_BACKGROUND_THREADS + ## value: "10" + ## + extraEnvVars: [] + ## @param provisioning.extraEnvVarsCM ConfigMap with extra environment variables + ## + extraEnvVarsCM: "" + ## @param provisioning.extraEnvVarsSecret Secret with extra environment variables + ## + extraEnvVarsSecret: "" + ## @param provisioning.podAnnotations Extra annotations for Kafka provisioning pods + ## + podAnnotations: {} + ## @param provisioning.podLabels Extra labels for Kafka provisioning pods + ## Ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + ## + podLabels: {} + ## Kafka provisioning pods ServiceAccount + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ + ## + serviceAccount: + ## @param provisioning.serviceAccount.create Enable creation of ServiceAccount for Kafka provisioning pods + ## + create: false + ## @param provisioning.serviceAccount.name The name of the service account to use. If not set and `create` is `true`, a name is generated + ## If not set and create is true, a name is generated using the provisioning.serviceAccount.name template + ## + name: "" + ## @param provisioning.serviceAccount.automountServiceAccountToken Allows auto mount of ServiceAccountToken on the serviceAccount created + ## Can be set to false if pods using this serviceAccount do not need to use K8s API + ## + automountServiceAccountToken: true + ## Kafka provisioning resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## @param provisioning.resources.limits The resources limits for the Kafka provisioning container + ## @param provisioning.resources.requests The requested resources for the Kafka provisioning container + ## + resources: + limits: {} + requests: {} + ## Kafka provisioning pods' Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod + ## @param provisioning.podSecurityContext.enabled Enable security context for the pods + ## @param provisioning.podSecurityContext.fsGroup Set Kafka provisioning pod's Security Context fsGroup + ## + podSecurityContext: + enabled: true + fsGroup: 1001 + ## Kafka provisioning containers' Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + ## @param provisioning.containerSecurityContext.enabled Enable Kafka provisioning containers' Security Context + ## @param provisioning.containerSecurityContext.runAsUser Set Kafka provisioning containers' Security Context runAsUser + ## @param provisioning.containerSecurityContext.runAsNonRoot Set Kafka provisioning containers' Security Context runAsNonRoot + ## e.g: + ## containerSecurityContext: + ## enabled: true + ## capabilities: + ## drop: ["NET_RAW"] + ## readOnlyRootFilesystem: true + ## + containerSecurityContext: + enabled: true + runAsUser: 1001 + runAsNonRoot: true + ## @param provisioning.schedulerName Name of the k8s scheduler (other than default) for kafka provisioning + ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ + ## + schedulerName: "" + ## @param provisioning.extraVolumes Optionally specify extra list of additional volumes for the Kafka provisioning pod(s) + ## e.g: + ## extraVolumes: + ## - name: kafka-jaas + ## secret: + ## secretName: kafka-jaas + ## + extraVolumes: [] + ## @param provisioning.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the Kafka provisioning container(s) + ## extraVolumeMounts: + ## - name: kafka-jaas + ## mountPath: /bitnami/kafka/config/kafka_jaas.conf + ## subPath: kafka_jaas.conf + ## + extraVolumeMounts: [] + ## @param provisioning.sidecars Add additional sidecar containers to the Kafka provisioning pod(s) + ## e.g: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + ## @param provisioning.initContainers Add additional Add init containers to the Kafka provisioning pod(s) + ## e.g: + ## initContainers: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + initContainers: [] + ## @param provisioning.waitForKafka If true use an init container to wait until kafka is ready before starting provisioning + ## + waitForKafka: true + +## @section ZooKeeper chart parameters + +## ZooKeeper chart configuration +## https://github.com/bitnami/charts/blob/main/bitnami/zookeeper/values.yaml +## +zookeeper: + ## @param zookeeper.enabled Switch to enable or disable the ZooKeeper helm chart + ## + enabled: true + ## @param zookeeper.replicaCount Number of ZooKeeper nodes + ## + replicaCount: 1 + ## ZooKeeper authenticaiton + ## + auth: + client: + ## @param zookeeper.auth.client.enabled Enable ZooKeeper auth + ## + enabled: false + ## @param zookeeper.auth.client.clientUser User that will use ZooKeeper clients to auth + ## + clientUser: "" + ## @param zookeeper.auth.client.clientPassword Password that will use ZooKeeper clients to auth + ## + clientPassword: "" + ## @param zookeeper.auth.client.serverUsers Comma, semicolon or whitespace separated list of user to be created. Specify them as a string, for example: "user1,user2,admin" + ## + serverUsers: "" + ## @param zookeeper.auth.client.serverPasswords Comma, semicolon or whitespace separated list of passwords to assign to users when created. Specify them as a string, for example: "pass4user1, pass4user2, pass4admin" + ## + serverPasswords: "" + ## ZooKeeper Persistence parameters + ## ref: https://kubernetes.io/docs/user-guide/persistent-volumes/ + ## @param zookeeper.persistence.enabled Enable persistence on ZooKeeper using PVC(s) + ## @param zookeeper.persistence.storageClass Persistent Volume storage class + ## @param zookeeper.persistence.accessModes Persistent Volume access modes + ## @param zookeeper.persistence.size Persistent Volume size + ## + persistence: + enabled: true + storageClass: "" + accessModes: + - ReadWriteOnce + size: 8Gi + +## External Zookeeper Configuration +## All of these values are only used if `zookeeper.enabled=false` +## +externalZookeeper: + ## @param externalZookeeper.servers List of external zookeeper servers to use. Typically used in combination with 'zookeeperChrootPath'. + ## + servers: [] diff --git a/deployment/deployment/middleware_deployment/redis-cluster/.helmignore b/deployment/charts/minio/.helmignore similarity index 100% rename from deployment/deployment/middleware_deployment/redis-cluster/.helmignore rename to deployment/charts/minio/.helmignore diff --git a/deployment/deployment/middleware_deployment/minio/Chart.yaml b/deployment/charts/minio/Chart.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/Chart.yaml rename to deployment/charts/minio/Chart.yaml diff --git a/deployment/deployment/middleware_deployment/minio/README.md b/deployment/charts/minio/README.md similarity index 100% rename from deployment/deployment/middleware_deployment/minio/README.md rename to deployment/charts/minio/README.md diff --git a/deployment/deployment/middleware_deployment/minio/ci/distributed-values.yaml b/deployment/charts/minio/ci/distributed-values.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/ci/distributed-values.yaml rename to deployment/charts/minio/ci/distributed-values.yaml diff --git a/deployment/deployment/middleware_deployment/minio/templates/NOTES.txt b/deployment/charts/minio/templates/NOTES.txt similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/NOTES.txt rename to deployment/charts/minio/templates/NOTES.txt diff --git a/deployment/deployment/middleware_deployment/minio/templates/_helper_create_bucket.txt b/deployment/charts/minio/templates/_helper_create_bucket.txt similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/_helper_create_bucket.txt rename to deployment/charts/minio/templates/_helper_create_bucket.txt diff --git a/deployment/deployment/middleware_deployment/minio/templates/_helpers.tpl b/deployment/charts/minio/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/_helpers.tpl rename to deployment/charts/minio/templates/_helpers.tpl diff --git a/deployment/deployment/middleware_deployment/minio/templates/configmap.yaml b/deployment/charts/minio/templates/configmap.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/configmap.yaml rename to deployment/charts/minio/templates/configmap.yaml diff --git a/deployment/deployment/middleware_deployment/minio/templates/deployment.yaml b/deployment/charts/minio/templates/deployment.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/deployment.yaml rename to deployment/charts/minio/templates/deployment.yaml diff --git a/deployment/deployment/middleware_deployment/minio/templates/ingress.yaml b/deployment/charts/minio/templates/ingress.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/ingress.yaml rename to deployment/charts/minio/templates/ingress.yaml diff --git a/deployment/deployment/middleware_deployment/minio/templates/networkpolicy.yaml b/deployment/charts/minio/templates/networkpolicy.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/networkpolicy.yaml rename to deployment/charts/minio/templates/networkpolicy.yaml diff --git a/deployment/deployment/middleware_deployment/minio/templates/poddisruptionbudget.yaml b/deployment/charts/minio/templates/poddisruptionbudget.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/poddisruptionbudget.yaml rename to deployment/charts/minio/templates/poddisruptionbudget.yaml diff --git a/deployment/deployment/middleware_deployment/minio/templates/post-install-create-bucket-job.yaml b/deployment/charts/minio/templates/post-install-create-bucket-job.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/post-install-create-bucket-job.yaml rename to deployment/charts/minio/templates/post-install-create-bucket-job.yaml diff --git a/deployment/deployment/middleware_deployment/minio/templates/post-install-prometheus-metrics-job.yaml b/deployment/charts/minio/templates/post-install-prometheus-metrics-job.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/post-install-prometheus-metrics-job.yaml rename to deployment/charts/minio/templates/post-install-prometheus-metrics-job.yaml diff --git a/deployment/deployment/middleware_deployment/minio/templates/post-install-prometheus-metrics-role.yaml b/deployment/charts/minio/templates/post-install-prometheus-metrics-role.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/post-install-prometheus-metrics-role.yaml rename to deployment/charts/minio/templates/post-install-prometheus-metrics-role.yaml diff --git a/deployment/deployment/middleware_deployment/minio/templates/post-install-prometheus-metrics-rolebinding.yaml b/deployment/charts/minio/templates/post-install-prometheus-metrics-rolebinding.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/post-install-prometheus-metrics-rolebinding.yaml rename to deployment/charts/minio/templates/post-install-prometheus-metrics-rolebinding.yaml diff --git a/deployment/deployment/middleware_deployment/minio/templates/post-install-prometheus-metrics-serviceaccount.yaml b/deployment/charts/minio/templates/post-install-prometheus-metrics-serviceaccount.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/post-install-prometheus-metrics-serviceaccount.yaml rename to deployment/charts/minio/templates/post-install-prometheus-metrics-serviceaccount.yaml diff --git a/deployment/deployment/middleware_deployment/minio/templates/pvc.yaml b/deployment/charts/minio/templates/pvc.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/pvc.yaml rename to deployment/charts/minio/templates/pvc.yaml diff --git a/deployment/deployment/middleware_deployment/minio/templates/secrets.yaml b/deployment/charts/minio/templates/secrets.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/secrets.yaml rename to deployment/charts/minio/templates/secrets.yaml diff --git a/deployment/deployment/middleware_deployment/minio/templates/service.yaml b/deployment/charts/minio/templates/service.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/service.yaml rename to deployment/charts/minio/templates/service.yaml diff --git a/deployment/deployment/middleware_deployment/minio/templates/serviceaccount.yaml b/deployment/charts/minio/templates/serviceaccount.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/serviceaccount.yaml rename to deployment/charts/minio/templates/serviceaccount.yaml diff --git a/deployment/deployment/middleware_deployment/minio/templates/servicemonitor.yaml b/deployment/charts/minio/templates/servicemonitor.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/servicemonitor.yaml rename to deployment/charts/minio/templates/servicemonitor.yaml diff --git a/deployment/deployment/middleware_deployment/minio/templates/statefulset.yaml b/deployment/charts/minio/templates/statefulset.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/templates/statefulset.yaml rename to deployment/charts/minio/templates/statefulset.yaml diff --git a/deployment/deployment/middleware_deployment/minio/values.yaml b/deployment/charts/minio/values.yaml similarity index 100% rename from deployment/deployment/middleware_deployment/minio/values.yaml rename to deployment/charts/minio/values.yaml diff --git a/deployment/deployment/middleware_deployment/zookeeper/.helmignore b/deployment/charts/mongodb/.helmignore similarity index 100% rename from deployment/deployment/middleware_deployment/zookeeper/.helmignore rename to deployment/charts/mongodb/.helmignore diff --git a/deployment/charts/mongodb/Chart.lock b/deployment/charts/mongodb/Chart.lock new file mode 100644 index 0000000..b2b23c8 --- /dev/null +++ b/deployment/charts/mongodb/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-13T00:01:58.474212991Z" diff --git a/deployment/charts/mongodb/Chart.yaml b/deployment/charts/mongodb/Chart.yaml new file mode 100644 index 0000000..d43901a --- /dev/null +++ b/deployment/charts/mongodb/Chart.yaml @@ -0,0 +1,30 @@ +annotations: + category: Database +apiVersion: v2 +appVersion: 6.0.3 +dependencies: +- name: common + repository: https://charts.bitnami.com/bitnami + tags: + - bitnami-common + version: 2.x.x +description: MongoDB(R) is a relational open source NoSQL database. Easy to use, it + stores data in JSON-like documents. Automated scalability and high-performance. + Ideal for developing cloud native applications. +home: https://github.com/bitnami/charts/tree/main/bitnami/mongodb +icon: https://bitnami.com/assets/stacks/mongodb/img/mongodb-stack-220x234.png +keywords: +- mongodb +- database +- nosql +- cluster +- replicaset +- replication +maintainers: +- name: Bitnami + url: https://github.com/bitnami/charts +name: mongodb +sources: +- https://github.com/bitnami/containers/tree/main/bitnami/mongodb +- https://mongodb.org +version: 13.6.2 diff --git a/deployment/charts/mongodb/README.md b/deployment/charts/mongodb/README.md new file mode 100644 index 0000000..7a98c7f --- /dev/null +++ b/deployment/charts/mongodb/README.md @@ -0,0 +1,795 @@ + + +# MongoDB(R) packaged by Bitnami + +MongoDB(R) is a relational open source NoSQL database. Easy to use, it stores data in JSON-like documents. Automated scalability and high-performance. Ideal for developing cloud native applications. + +[Overview of MongoDB®](http://www.mongodb.org) + +Disclaimer: The respective trademarks mentioned in the offering are owned by the respective companies. We do not provide a commercial license for any of these products. This listing has an open-source license. MongoDB(R) is run and maintained by MongoDB, which is a completely separate project from Bitnami. + +## TL;DR + +```bash +$ helm repo add my-repo https://charts.bitnami.com/bitnami +$ helm install my-release my-repo/mongodb +``` + +## Introduction + +This chart bootstraps a [MongoDB(®)](https://github.com/bitnami/containers/tree/main/bitnami/mongodb) deployment on a [Kubernetes](https://kubernetes.io) cluster using the [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+ +- 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/mongodb +``` + +The command deploys MongoDB(®) 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. + +## Architecture + +This chart allows installing MongoDB(®) using two different architecture setups: `standalone` or `replicaset`. Use the `architecture` parameter to choose the one to use: + +```console +architecture="standalone" +architecture="replicaset" +``` + +Refer to the [chart documentation for more information on each of these architectures](https://docs.bitnami.com/kubernetes/infrastructure/mongodb/get-started/understand-architecture/). + +## 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 StorageClass for Persistent Volume(s) | `""` | +| `global.namespaceOverride` | Override the namespace for resource deployed by the chart, but can itself be overridden by the local namespaceOverride | `""` | + + +### Common parameters + +| Name | Description | Value | +| ------------------------ | --------------------------------------------------------------------------------------------------------- | --------------- | +| `nameOverride` | String to partially override mongodb.fullname template (will maintain the release name) | `""` | +| `fullnameOverride` | String to fully override mongodb.fullname template | `""` | +| `namespaceOverride` | String to fully override common.names.namespace | `""` | +| `kubeVersion` | Force target Kubernetes version (using Helm capabilities if not set) | `""` | +| `clusterDomain` | Default Kubernetes cluster domain | `cluster.local` | +| `extraDeploy` | Array of extra objects to deploy with the release | `[]` | +| `commonLabels` | Add labels to all the deployed resources (sub-charts are not considered). Evaluated as a template | `{}` | +| `commonAnnotations` | Common annotations to add to all Mongo resources (sub-charts are not considered). Evaluated as a template | `{}` | +| `topologyKey` | Override common lib default topology key. If empty - "kubernetes.io/hostname" is used | `""` | +| `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"]` | + + +### MongoDB(®) parameters + +| Name | Description | Value | +| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------- | +| `image.registry` | MongoDB(®) image registry | `docker.io` | +| `image.repository` | MongoDB(®) image registry | `bitnami/mongodb` | +| `image.tag` | MongoDB(®) image tag (immutable tags are recommended) | `6.0.3-debian-11-r9` | +| `image.digest` | MongoDB(®) image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | +| `image.pullPolicy` | MongoDB(®) image pull policy | `IfNotPresent` | +| `image.pullSecrets` | Specify docker-registry secret names as an array | `[]` | +| `image.debug` | Set to true if you would like to see extra information on logs | `false` | +| `schedulerName` | Name of the scheduler (other than default) to dispatch pods | `""` | +| `architecture` | MongoDB(®) architecture (`standalone` or `replicaset`) | `standalone` | +| `useStatefulSet` | Set to true to use a StatefulSet instead of a Deployment (only when `architecture=standalone`) | `false` | +| `auth.enabled` | Enable authentication | `true` | +| `auth.rootUser` | MongoDB(®) root user | `root` | +| `auth.rootPassword` | MongoDB(®) root password | `""` | +| `auth.usernames` | List of custom users to be created during the initialization | `[]` | +| `auth.passwords` | List of passwords for the custom users set at `auth.usernames` | `[]` | +| `auth.databases` | List of custom databases to be created during the initialization | `[]` | +| `auth.username` | DEPRECATED: use `auth.usernames` instead | `""` | +| `auth.password` | DEPRECATED: use `auth.passwords` instead | `""` | +| `auth.database` | DEPRECATED: use `auth.databases` instead | `""` | +| `auth.replicaSetKey` | Key used for authentication in the replicaset (only when `architecture=replicaset`) | `""` | +| `auth.existingSecret` | Existing secret with MongoDB(®) credentials (keys: `mongodb-passwords`, `mongodb-root-password`, `mongodb-metrics-password`, ` mongodb-replica-set-key`) | `""` | +| `tls.enabled` | Enable MongoDB(®) TLS support between nodes in the cluster as well as between mongo clients and nodes | `false` | +| `tls.autoGenerated` | Generate a custom CA and self-signed certificates | `true` | +| `tls.existingSecret` | Existing secret with TLS certificates (keys: `mongodb-ca-cert`, `mongodb-ca-key`) | `""` | +| `tls.caCert` | Custom CA certificated (base64 encoded) | `""` | +| `tls.caKey` | CA certificate private key (base64 encoded) | `""` | +| `tls.standalone.existingSecret` | Existing secret with TLS certificates (`tls.key`, `tls.crt`, `ca.crt`). | `""` | +| `tls.replicaset.existingSecrets` | Array of existing secrets with TLS certificates (`tls.key`, `tls.crt`, `ca.crt`). | `[]` | +| `tls.hidden.existingSecrets` | Array of existing secrets with TLS certificates (`tls.key`, `tls.crt`, `ca.crt`). | `[]` | +| `tls.arbiter.existingSecret` | Existing secret with TLS certificates (`tls.key`, `tls.crt`, `ca.crt`). | `""` | +| `tls.image.registry` | Init container TLS certs setup image registry | `docker.io` | +| `tls.image.repository` | Init container TLS certs setup image repository | `bitnami/nginx` | +| `tls.image.tag` | Init container TLS certs setup image tag (immutable tags are recommended) | `1.23.2-debian-11-r18` | +| `tls.image.digest` | Init container TLS certs setup image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | +| `tls.image.pullPolicy` | Init container TLS certs setup image pull policy | `IfNotPresent` | +| `tls.image.pullSecrets` | Init container TLS certs specify docker-registry secret names as an array | `[]` | +| `tls.extraDnsNames` | Add extra dns names to the CA, can solve x509 auth issue for pod clients | `[]` | +| `tls.mode` | Allows to set the tls mode which should be used when tls is enabled (options: `allowTLS`, `preferTLS`, `requireTLS`) | `requireTLS` | +| `tls.resources.limits` | Init container generate-tls-certs resource limits | `{}` | +| `tls.resources.requests` | Init container generate-tls-certs resource requests | `{}` | +| `hostAliases` | Add deployment host aliases | `[]` | +| `replicaSetName` | Name of the replica set (only when `architecture=replicaset`) | `rs0` | +| `replicaSetHostnames` | Enable DNS hostnames in the replicaset config (only when `architecture=replicaset`) | `true` | +| `enableIPv6` | Switch to enable/disable IPv6 on MongoDB(®) | `false` | +| `directoryPerDB` | Switch to enable/disable DirectoryPerDB on MongoDB(®) | `false` | +| `systemLogVerbosity` | MongoDB(®) system log verbosity level | `0` | +| `disableSystemLog` | Switch to enable/disable MongoDB(®) system log | `false` | +| `disableJavascript` | Switch to enable/disable MongoDB(®) server-side JavaScript execution | `false` | +| `enableJournal` | Switch to enable/disable MongoDB(®) Journaling | `true` | +| `configuration` | MongoDB(®) configuration file to be used for Primary and Secondary nodes | `""` | + + +### replicaSetConfigurationSettings settings applied during runtime (not via configuration file) + +| Name | Description | Value | +| ----------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------- | +| `replicaSetConfigurationSettings.enabled` | Enable MongoDB(®) Switch to enable/disable configuring MongoDB(®) run time rs.conf settings | `false` | +| `replicaSetConfigurationSettings.configuration` | run-time rs.conf settings | `{}` | +| `existingConfigmap` | Name of existing ConfigMap with MongoDB(®) configuration for Primary and Secondary nodes | `""` | +| `initdbScripts` | Dictionary of initdb scripts | `{}` | +| `initdbScriptsConfigMap` | Existing ConfigMap with custom initdb scripts | `""` | +| `command` | Override default container command (useful when using custom images) | `[]` | +| `args` | Override default container args (useful when using custom images) | `[]` | +| `extraFlags` | MongoDB(®) additional command line flags | `[]` | +| `extraEnvVars` | Extra environment variables to add to MongoDB(®) pods | `[]` | +| `extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars | `""` | +| `extraEnvVarsSecret` | Name of existing Secret containing extra env vars (in case of sensitive data) | `""` | + + +### MongoDB(®) statefulset parameters + +| Name | Description | Value | +| --------------------------------------- | --------------------------------------------------------------------------------------------------------------- | --------------- | +| `annotations` | Additional labels to be added to the MongoDB(®) statefulset. Evaluated as a template | `{}` | +| `labels` | Annotations to be added to the MongoDB(®) statefulset. Evaluated as a template | `{}` | +| `replicaCount` | Number of MongoDB(®) nodes (only when `architecture=replicaset`) | `2` | +| `updateStrategy.type` | Strategy to use to replace existing MongoDB(®) pods. When architecture=standalone and useStatefulSet=false, | `RollingUpdate` | +| `podManagementPolicy` | Pod management policy for MongoDB(®) | `OrderedReady` | +| `podAffinityPreset` | MongoDB(®) Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `podAntiAffinityPreset` | MongoDB(®) Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `nodeAffinityPreset.type` | MongoDB(®) Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `nodeAffinityPreset.key` | MongoDB(®) Node label key to match Ignored if `affinity` is set. | `""` | +| `nodeAffinityPreset.values` | MongoDB(®) Node label values to match. Ignored if `affinity` is set. | `[]` | +| `affinity` | MongoDB(®) Affinity for pod assignment | `{}` | +| `nodeSelector` | MongoDB(®) Node labels for pod assignment | `{}` | +| `tolerations` | MongoDB(®) Tolerations for pod assignment | `[]` | +| `topologySpreadConstraints` | MongoDB(®) Spread Constraints for Pods | `[]` | +| `lifecycleHooks` | LifecycleHook for the MongoDB(®) container(s) to automate configuration before or after startup | `{}` | +| `terminationGracePeriodSeconds` | MongoDB(®) Termination Grace Period | `""` | +| `podLabels` | MongoDB(®) pod labels | `{}` | +| `podAnnotations` | MongoDB(®) Pod annotations | `{}` | +| `priorityClassName` | Name of the existing priority class to be used by MongoDB(®) pod(s) | `""` | +| `runtimeClassName` | Name of the runtime class to be used by MongoDB(®) pod(s) | `""` | +| `podSecurityContext.enabled` | Enable MongoDB(®) pod(s)' Security Context | `true` | +| `podSecurityContext.fsGroup` | Group ID for the volumes of the MongoDB(®) pod(s) | `1001` | +| `podSecurityContext.sysctls` | sysctl settings of the MongoDB(®) pod(s)' | `[]` | +| `containerSecurityContext.enabled` | Enable MongoDB(®) container(s)' Security Context | `true` | +| `containerSecurityContext.runAsUser` | User ID for the MongoDB(®) container | `1001` | +| `containerSecurityContext.runAsNonRoot` | Set MongoDB(®) container's Security Context runAsNonRoot | `true` | +| `resources.limits` | The resources limits for MongoDB(®) containers | `{}` | +| `resources.requests` | The requested resources for MongoDB(®) containers | `{}` | +| `containerPorts.mongodb` | MongoDB(®) container port | `27017` | +| `livenessProbe.enabled` | Enable livenessProbe | `true` | +| `livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `30` | +| `livenessProbe.periodSeconds` | Period seconds for livenessProbe | `20` | +| `livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `10` | +| `livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `6` | +| `livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | +| `readinessProbe.enabled` | Enable readinessProbe | `true` | +| `readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `5` | +| `readinessProbe.periodSeconds` | Period seconds for readinessProbe | `10` | +| `readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `5` | +| `readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `6` | +| `readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | +| `startupProbe.enabled` | Enable startupProbe | `false` | +| `startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `5` | +| `startupProbe.periodSeconds` | Period seconds for startupProbe | `20` | +| `startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `10` | +| `startupProbe.failureThreshold` | Failure threshold for startupProbe | `30` | +| `startupProbe.successThreshold` | Success threshold for startupProbe | `1` | +| `customLivenessProbe` | Override default liveness probe for MongoDB(®) containers | `{}` | +| `customReadinessProbe` | Override default readiness probe for MongoDB(®) containers | `{}` | +| `customStartupProbe` | Override default startup probe for MongoDB(®) containers | `{}` | +| `initContainers` | Add additional init containers for the hidden node pod(s) | `[]` | +| `sidecars` | Add additional sidecar containers for the MongoDB(®) pod(s) | `[]` | +| `extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the MongoDB(®) container(s) | `[]` | +| `extraVolumes` | Optionally specify extra list of additional volumes to the MongoDB(®) statefulset | `[]` | +| `pdb.create` | Enable/disable a Pod Disruption Budget creation for MongoDB(®) pod(s) | `false` | +| `pdb.minAvailable` | Minimum number/percentage of MongoDB(®) pods that must still be available after the eviction | `1` | +| `pdb.maxUnavailable` | Maximum number/percentage of MongoDB(®) pods that may be made unavailable after the eviction | `""` | + + +### Traffic exposure parameters + +| Name | Description | Value | +| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | +| `service.nameOverride` | MongoDB(®) service name | `""` | +| `service.type` | Kubernetes Service type (only for standalone architecture) | `ClusterIP` | +| `service.portName` | MongoDB(®) service port name (only for standalone architecture) | `mongodb` | +| `service.ports.mongodb` | MongoDB(®) service port. | `27017` | +| `service.nodePorts.mongodb` | Port to bind to for NodePort and LoadBalancer service types (only for standalone architecture) | `""` | +| `service.clusterIP` | MongoDB(®) service cluster IP (only for standalone architecture) | `""` | +| `service.externalIPs` | Specify the externalIP value ClusterIP service type (only for standalone architecture) | `[]` | +| `service.loadBalancerIP` | loadBalancerIP for MongoDB(®) Service (only for standalone architecture) | `""` | +| `service.loadBalancerClass` | loadBalancerClass for MongoDB(®) Service (only for standalone architecture) | `""` | +| `service.loadBalancerSourceRanges` | Address(es) that are allowed when service is LoadBalancer (only for standalone architecture) | `[]` | +| `service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | +| `service.annotations` | Provide any additional annotations that may be required | `{}` | +| `service.externalTrafficPolicy` | service external traffic policy (only for standalone architecture) | `Local` | +| `service.sessionAffinity` | Control where client requests go, to the same pod or round-robin | `None` | +| `service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | +| `externalAccess.enabled` | Enable Kubernetes external cluster access to MongoDB(®) nodes (only for replicaset architecture) | `false` | +| `externalAccess.autoDiscovery.enabled` | Enable using an init container to auto-detect external IPs by querying the K8s API | `false` | +| `externalAccess.autoDiscovery.image.registry` | Init container auto-discovery image registry | `docker.io` | +| `externalAccess.autoDiscovery.image.repository` | Init container auto-discovery image repository | `bitnami/kubectl` | +| `externalAccess.autoDiscovery.image.tag` | Init container auto-discovery image tag (immutable tags are recommended) | `1.25.5-debian-11-r0` | +| `externalAccess.autoDiscovery.image.digest` | Init container auto-discovery image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | +| `externalAccess.autoDiscovery.image.pullPolicy` | Init container auto-discovery image pull policy | `IfNotPresent` | +| `externalAccess.autoDiscovery.image.pullSecrets` | Init container auto-discovery image pull secrets | `[]` | +| `externalAccess.autoDiscovery.resources.limits` | Init container auto-discovery resource limits | `{}` | +| `externalAccess.autoDiscovery.resources.requests` | Init container auto-discovery resource requests | `{}` | +| `externalAccess.service.type` | Kubernetes Service type for external access. Allowed values: NodePort, LoadBalancer or ClusterIP | `LoadBalancer` | +| `externalAccess.service.portName` | MongoDB(®) port name used for external access when service type is LoadBalancer | `mongodb` | +| `externalAccess.service.ports.mongodb` | MongoDB(®) port used for external access when service type is LoadBalancer | `27017` | +| `externalAccess.service.loadBalancerIPs` | Array of load balancer IPs for MongoDB(®) nodes | `[]` | +| `externalAccess.service.loadBalancerClass` | loadBalancerClass when service type is LoadBalancer | `""` | +| `externalAccess.service.loadBalancerSourceRanges` | Address(es) that are allowed when service is LoadBalancer | `[]` | +| `externalAccess.service.externalTrafficPolicy` | MongoDB(®) service external traffic policy | `Local` | +| `externalAccess.service.nodePorts` | Array of node ports used to configure MongoDB(®) advertised hostname when service type is NodePort | `[]` | +| `externalAccess.service.domain` | Domain or external IP used to configure MongoDB(®) advertised hostname when service type is NodePort | `""` | +| `externalAccess.service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | +| `externalAccess.service.annotations` | Service annotations for external access | `{}` | +| `externalAccess.service.sessionAffinity` | Control where client requests go, to the same pod or round-robin | `None` | +| `externalAccess.service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | +| `externalAccess.hidden.enabled` | Enable Kubernetes external cluster access to MongoDB(®) hidden nodes | `false` | +| `externalAccess.hidden.service.type` | Kubernetes Service type for external access. Allowed values: NodePort or LoadBalancer | `LoadBalancer` | +| `externalAccess.hidden.service.portName` | MongoDB(®) port name used for external access when service type is LoadBalancer | `mongodb` | +| `externalAccess.hidden.service.ports.mongodb` | MongoDB(®) port used for external access when service type is LoadBalancer | `27017` | +| `externalAccess.hidden.service.loadBalancerIPs` | Array of load balancer IPs for MongoDB(®) nodes | `[]` | +| `externalAccess.hidden.service.loadBalancerClass` | loadBalancerClass when service type is LoadBalancer | `""` | +| `externalAccess.hidden.service.loadBalancerSourceRanges` | Address(es) that are allowed when service is LoadBalancer | `[]` | +| `externalAccess.hidden.service.externalTrafficPolicy` | MongoDB(®) service external traffic policy | `Local` | +| `externalAccess.hidden.service.nodePorts` | Array of node ports used to configure MongoDB(®) advertised hostname when service type is NodePort. Length must be the same as replicaCount | `[]` | +| `externalAccess.hidden.service.domain` | Domain or external IP used to configure MongoDB(®) advertised hostname when service type is NodePort | `""` | +| `externalAccess.hidden.service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | +| `externalAccess.hidden.service.annotations` | Service annotations for external access | `{}` | +| `externalAccess.hidden.service.sessionAffinity` | Control where client requests go, to the same pod or round-robin | `None` | +| `externalAccess.hidden.service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | + + +### Persistence parameters + +| Name | Description | Value | +| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | +| `persistence.enabled` | Enable MongoDB(®) data persistence using PVC | `true` | +| `persistence.medium` | Provide a medium for `emptyDir` volumes. | `""` | +| `persistence.existingClaim` | Provide an existing `PersistentVolumeClaim` (only when `architecture=standalone`) | `""` | +| `persistence.resourcePolicy` | Setting it to "keep" to avoid removing PVCs during a helm delete operation. Leaving it empty will delete PVCs after the chart deleted | `""` | +| `persistence.storageClass` | PVC Storage Class for MongoDB(®) data volume | `""` | +| `persistence.accessModes` | PV Access Mode | `["ReadWriteOnce"]` | +| `persistence.size` | PVC Storage Request for MongoDB(®) data volume | `8Gi` | +| `persistence.annotations` | PVC annotations | `{}` | +| `persistence.mountPath` | Path to mount the volume at | `/bitnami/mongodb` | +| `persistence.subPath` | Subdirectory of the volume to mount at | `""` | +| `persistence.volumeClaimTemplates.selector` | A label query over volumes to consider for binding (e.g. when using local volumes) | `{}` | +| `persistence.volumeClaimTemplates.requests` | Custom PVC requests attributes | `{}` | +| `persistence.volumeClaimTemplates.dataSource` | Add dataSource to the VolumeClaimTemplate | `{}` | + + +### RBAC parameters + +| Name | Description | Value | +| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| `serviceAccount.create` | Enable creation of ServiceAccount for MongoDB(®) pods | `true` | +| `serviceAccount.name` | Name of the created serviceAccount | `""` | +| `serviceAccount.annotations` | Additional Service Account annotations | `{}` | +| `serviceAccount.automountServiceAccountToken` | Allows auto mount of ServiceAccountToken on the serviceAccount created | `true` | +| `rbac.create` | Whether to create & use RBAC resources or not | `false` | +| `rbac.rules` | Custom rules to create following the role specification | `[]` | +| `podSecurityPolicy.create` | Whether to create a PodSecurityPolicy. WARNING: PodSecurityPolicy is deprecated in Kubernetes v1.21 or later, unavailable in v1.25 or later | `false` | +| `podSecurityPolicy.allowPrivilegeEscalation` | Enable privilege escalation | `false` | +| `podSecurityPolicy.privileged` | Allow privileged | `false` | +| `podSecurityPolicy.spec` | Specify the full spec to use for Pod Security Policy | `{}` | + + +### 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 | `{}` | +| `volumePermissions.securityContext.runAsUser` | User ID for the volumePermissions container | `0` | + + +### Arbiter parameters + +| Name | Description | Value | +| ----------------------------------------------- | ------------------------------------------------------------------------------------------------- | --------------- | +| `arbiter.enabled` | Enable deploying the arbiter | `true` | +| `arbiter.hostAliases` | Add deployment host aliases | `[]` | +| `arbiter.configuration` | Arbiter configuration file to be used | `""` | +| `arbiter.existingConfigmap` | Name of existing ConfigMap with Arbiter configuration | `""` | +| `arbiter.command` | Override default container command (useful when using custom images) | `[]` | +| `arbiter.args` | Override default container args (useful when using custom images) | `[]` | +| `arbiter.extraFlags` | Arbiter additional command line flags | `[]` | +| `arbiter.extraEnvVars` | Extra environment variables to add to Arbiter pods | `[]` | +| `arbiter.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars | `""` | +| `arbiter.extraEnvVarsSecret` | Name of existing Secret containing extra env vars (in case of sensitive data) | `""` | +| `arbiter.annotations` | Additional labels to be added to the Arbiter statefulset | `{}` | +| `arbiter.labels` | Annotations to be added to the Arbiter statefulset | `{}` | +| `arbiter.topologySpreadConstraints` | MongoDB(®) Spread Constraints for arbiter Pods | `[]` | +| `arbiter.lifecycleHooks` | LifecycleHook for the Arbiter container to automate configuration before or after startup | `{}` | +| `arbiter.terminationGracePeriodSeconds` | Arbiter Termination Grace Period | `""` | +| `arbiter.updateStrategy.type` | Strategy that will be employed to update Pods in the StatefulSet | `RollingUpdate` | +| `arbiter.podManagementPolicy` | Pod management policy for MongoDB(®) | `OrderedReady` | +| `arbiter.schedulerName` | Name of the scheduler (other than default) to dispatch pods | `""` | +| `arbiter.podAffinityPreset` | Arbiter Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `arbiter.podAntiAffinityPreset` | Arbiter Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `arbiter.nodeAffinityPreset.type` | Arbiter Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `arbiter.nodeAffinityPreset.key` | Arbiter Node label key to match Ignored if `affinity` is set. | `""` | +| `arbiter.nodeAffinityPreset.values` | Arbiter Node label values to match. Ignored if `affinity` is set. | `[]` | +| `arbiter.affinity` | Arbiter Affinity for pod assignment | `{}` | +| `arbiter.nodeSelector` | Arbiter Node labels for pod assignment | `{}` | +| `arbiter.tolerations` | Arbiter Tolerations for pod assignment | `[]` | +| `arbiter.podLabels` | Arbiter pod labels | `{}` | +| `arbiter.podAnnotations` | Arbiter Pod annotations | `{}` | +| `arbiter.priorityClassName` | Name of the existing priority class to be used by Arbiter pod(s) | `""` | +| `arbiter.runtimeClassName` | Name of the runtime class to be used by Arbiter pod(s) | `""` | +| `arbiter.podSecurityContext.enabled` | Enable Arbiter pod(s)' Security Context | `true` | +| `arbiter.podSecurityContext.fsGroup` | Group ID for the volumes of the Arbiter pod(s) | `1001` | +| `arbiter.podSecurityContext.sysctls` | sysctl settings of the Arbiter pod(s)' | `[]` | +| `arbiter.containerSecurityContext.enabled` | Enable Arbiter container(s)' Security Context | `true` | +| `arbiter.containerSecurityContext.runAsUser` | User ID for the Arbiter container | `1001` | +| `arbiter.containerSecurityContext.runAsNonRoot` | Set Arbiter containers' Security Context runAsNonRoot | `true` | +| `arbiter.resources.limits` | The resources limits for Arbiter containers | `{}` | +| `arbiter.resources.requests` | The requested resources for Arbiter containers | `{}` | +| `arbiter.containerPorts.mongodb` | MongoDB(®) arbiter container port | `27017` | +| `arbiter.livenessProbe.enabled` | Enable livenessProbe | `true` | +| `arbiter.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `30` | +| `arbiter.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `20` | +| `arbiter.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `10` | +| `arbiter.livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `6` | +| `arbiter.livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | +| `arbiter.readinessProbe.enabled` | Enable readinessProbe | `true` | +| `arbiter.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `5` | +| `arbiter.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `20` | +| `arbiter.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `10` | +| `arbiter.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `6` | +| `arbiter.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | +| `arbiter.startupProbe.enabled` | Enable startupProbe | `false` | +| `arbiter.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `5` | +| `arbiter.startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | +| `arbiter.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `5` | +| `arbiter.startupProbe.failureThreshold` | Failure threshold for startupProbe | `30` | +| `arbiter.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | +| `arbiter.customLivenessProbe` | Override default liveness probe for Arbiter containers | `{}` | +| `arbiter.customReadinessProbe` | Override default readiness probe for Arbiter containers | `{}` | +| `arbiter.customStartupProbe` | Override default startup probe for Arbiter containers | `{}` | +| `arbiter.initContainers` | Add additional init containers for the Arbiter pod(s) | `[]` | +| `arbiter.sidecars` | Add additional sidecar containers for the Arbiter pod(s) | `[]` | +| `arbiter.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the Arbiter container(s) | `[]` | +| `arbiter.extraVolumes` | Optionally specify extra list of additional volumes to the Arbiter statefulset | `[]` | +| `arbiter.pdb.create` | Enable/disable a Pod Disruption Budget creation for Arbiter pod(s) | `false` | +| `arbiter.pdb.minAvailable` | Minimum number/percentage of Arbiter pods that should remain scheduled | `1` | +| `arbiter.pdb.maxUnavailable` | Maximum number/percentage of Arbiter pods that may be made unavailable | `""` | +| `arbiter.service.nameOverride` | The arbiter service name | `""` | +| `arbiter.service.ports.mongodb` | MongoDB(®) service port | `27017` | +| `arbiter.service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | +| `arbiter.service.annotations` | Provide any additional annotations that may be required | `{}` | + + +### Hidden Node parameters + +| Name | Description | Value | +| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------- | +| `hidden.enabled` | Enable deploying the hidden nodes | `false` | +| `hidden.hostAliases` | Add deployment host aliases | `[]` | +| `hidden.configuration` | Hidden node configuration file to be used | `""` | +| `hidden.existingConfigmap` | Name of existing ConfigMap with Hidden node configuration | `""` | +| `hidden.command` | Override default container command (useful when using custom images) | `[]` | +| `hidden.args` | Override default container args (useful when using custom images) | `[]` | +| `hidden.extraFlags` | Hidden node additional command line flags | `[]` | +| `hidden.extraEnvVars` | Extra environment variables to add to Hidden node pods | `[]` | +| `hidden.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars | `""` | +| `hidden.extraEnvVarsSecret` | Name of existing Secret containing extra env vars (in case of sensitive data) | `""` | +| `hidden.annotations` | Additional labels to be added to thehidden node statefulset | `{}` | +| `hidden.labels` | Annotations to be added to the hidden node statefulset | `{}` | +| `hidden.topologySpreadConstraints` | MongoDB(®) Spread Constraints for hidden Pods | `[]` | +| `hidden.lifecycleHooks` | LifecycleHook for the Hidden container to automate configuration before or after startup | `{}` | +| `hidden.replicaCount` | Number of hidden nodes (only when `architecture=replicaset`) | `1` | +| `hidden.terminationGracePeriodSeconds` | Hidden Termination Grace Period | `""` | +| `hidden.updateStrategy.type` | Strategy that will be employed to update Pods in the StatefulSet | `RollingUpdate` | +| `hidden.podManagementPolicy` | Pod management policy for hidden node | `OrderedReady` | +| `hidden.schedulerName` | Name of the scheduler (other than default) to dispatch pods | `""` | +| `hidden.podAffinityPreset` | Hidden node Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `hidden.podAntiAffinityPreset` | Hidden node Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `hidden.nodeAffinityPreset.type` | Hidden Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `hidden.nodeAffinityPreset.key` | Hidden Node label key to match Ignored if `affinity` is set. | `""` | +| `hidden.nodeAffinityPreset.values` | Hidden Node label values to match. Ignored if `affinity` is set. | `[]` | +| `hidden.affinity` | Hidden node Affinity for pod assignment | `{}` | +| `hidden.nodeSelector` | Hidden node Node labels for pod assignment | `{}` | +| `hidden.tolerations` | Hidden node Tolerations for pod assignment | `[]` | +| `hidden.podLabels` | Hidden node pod labels | `{}` | +| `hidden.podAnnotations` | Hidden node Pod annotations | `{}` | +| `hidden.priorityClassName` | Name of the existing priority class to be used by hidden node pod(s) | `""` | +| `hidden.runtimeClassName` | Name of the runtime class to be used by hidden node pod(s) | `""` | +| `hidden.podSecurityContext.enabled` | Enable Hidden pod(s)' Security Context | `true` | +| `hidden.podSecurityContext.fsGroup` | Group ID for the volumes of the Hidden pod(s) | `1001` | +| `hidden.podSecurityContext.sysctls` | sysctl settings of the Hidden pod(s)' | `[]` | +| `hidden.containerSecurityContext.enabled` | Enable Hidden container(s)' Security Context | `true` | +| `hidden.containerSecurityContext.runAsUser` | User ID for the Hidden container | `1001` | +| `hidden.containerSecurityContext.runAsNonRoot` | Set Hidden containers' Security Context runAsNonRoot | `true` | +| `hidden.resources.limits` | The resources limits for hidden node containers | `{}` | +| `hidden.resources.requests` | The requested resources for hidden node containers | `{}` | +| `hidden.containerPorts.mongodb` | MongoDB(®) hidden container port | `27017` | +| `hidden.livenessProbe.enabled` | Enable livenessProbe | `true` | +| `hidden.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `30` | +| `hidden.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `20` | +| `hidden.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `10` | +| `hidden.livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `6` | +| `hidden.livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | +| `hidden.readinessProbe.enabled` | Enable readinessProbe | `true` | +| `hidden.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `5` | +| `hidden.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `20` | +| `hidden.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `10` | +| `hidden.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `6` | +| `hidden.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | +| `hidden.startupProbe.enabled` | Enable startupProbe | `false` | +| `hidden.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `5` | +| `hidden.startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | +| `hidden.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `5` | +| `hidden.startupProbe.failureThreshold` | Failure threshold for startupProbe | `30` | +| `hidden.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | +| `hidden.customLivenessProbe` | Override default liveness probe for hidden node containers | `{}` | +| `hidden.customReadinessProbe` | Override default readiness probe for hidden node containers | `{}` | +| `hidden.customStartupProbe` | Override default startup probe for MongoDB(®) containers | `{}` | +| `hidden.initContainers` | Add init containers to the MongoDB(®) Hidden pods. | `[]` | +| `hidden.sidecars` | Add additional sidecar containers for the hidden node pod(s) | `[]` | +| `hidden.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the hidden node container(s) | `[]` | +| `hidden.extraVolumes` | Optionally specify extra list of additional volumes to the hidden node statefulset | `[]` | +| `hidden.pdb.create` | Enable/disable a Pod Disruption Budget creation for hidden node pod(s) | `false` | +| `hidden.pdb.minAvailable` | Minimum number/percentage of hidden node pods that should remain scheduled | `1` | +| `hidden.pdb.maxUnavailable` | Maximum number/percentage of hidden node pods that may be made unavailable | `""` | +| `hidden.persistence.enabled` | Enable hidden node data persistence using PVC | `true` | +| `hidden.persistence.medium` | Provide a medium for `emptyDir` volumes. | `""` | +| `hidden.persistence.storageClass` | PVC Storage Class for hidden node data volume | `""` | +| `hidden.persistence.accessModes` | PV Access Mode | `["ReadWriteOnce"]` | +| `hidden.persistence.size` | PVC Storage Request for hidden node data volume | `8Gi` | +| `hidden.persistence.annotations` | PVC annotations | `{}` | +| `hidden.persistence.mountPath` | The path the volume will be mounted at, useful when using different MongoDB(®) images. | `/bitnami/mongodb` | +| `hidden.persistence.subPath` | The subdirectory of the volume to mount to, useful in dev environments | `""` | +| `hidden.persistence.volumeClaimTemplates.selector` | A label query over volumes to consider for binding (e.g. when using local volumes) | `{}` | +| `hidden.persistence.volumeClaimTemplates.requests` | Custom PVC requests attributes | `{}` | +| `hidden.persistence.volumeClaimTemplates.dataSource` | Set volumeClaimTemplate dataSource | `{}` | +| `hidden.service.portName` | MongoDB(®) service port name | `mongodb` | +| `hidden.service.ports.mongodb` | MongoDB(®) service port | `27017` | +| `hidden.service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | +| `hidden.service.annotations` | Provide any additional annotations that may be required | `{}` | + + +### Metrics parameters + +| Name | Description | Value | +| -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | -------------------------- | +| `metrics.enabled` | Enable using a sidecar Prometheus exporter | `false` | +| `metrics.image.registry` | MongoDB(®) Prometheus exporter image registry | `docker.io` | +| `metrics.image.repository` | MongoDB(®) Prometheus exporter image repository | `bitnami/mongodb-exporter` | +| `metrics.image.tag` | MongoDB(®) Prometheus exporter image tag (immutable tags are recommended) | `0.35.0-debian-11-r14` | +| `metrics.image.digest` | MongoDB(®) image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | +| `metrics.image.pullPolicy` | MongoDB(®) Prometheus exporter image pull policy | `IfNotPresent` | +| `metrics.image.pullSecrets` | Specify docker-registry secret names as an array | `[]` | +| `metrics.username` | String with username for the metrics exporter | `""` | +| `metrics.password` | String with password for the metrics exporter | `""` | +| `metrics.extraFlags` | String with extra flags to the metrics exporter | `""` | +| `metrics.command` | Override default container command (useful when using custom images) | `[]` | +| `metrics.args` | Override default container args (useful when using custom images) | `[]` | +| `metrics.resources.limits` | The resources limits for Prometheus exporter containers | `{}` | +| `metrics.resources.requests` | The requested resources for Prometheus exporter containers | `{}` | +| `metrics.containerPort` | Port of the Prometheus metrics container | `9216` | +| `metrics.service.annotations` | Annotations for Prometheus Exporter pods. Evaluated as a template. | `{}` | +| `metrics.service.type` | Type of the Prometheus metrics service | `ClusterIP` | +| `metrics.service.ports.metrics` | Port of the Prometheus metrics service | `9216` | +| `metrics.service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | +| `metrics.livenessProbe.enabled` | Enable livenessProbe | `true` | +| `metrics.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `15` | +| `metrics.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `5` | +| `metrics.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `5` | +| `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 | `5` | +| `metrics.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `5` | +| `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.startupProbe.enabled` | Enable startupProbe | `false` | +| `metrics.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `5` | +| `metrics.startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | +| `metrics.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `5` | +| `metrics.startupProbe.failureThreshold` | Failure threshold for startupProbe | `30` | +| `metrics.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | +| `metrics.customLivenessProbe` | Override default liveness probe for MongoDB(®) containers | `{}` | +| `metrics.customReadinessProbe` | Override default readiness probe for MongoDB(®) containers | `{}` | +| `metrics.customStartupProbe` | Override default startup probe for MongoDB(®) containers | `{}` | +| `metrics.serviceMonitor.enabled` | Create ServiceMonitor Resource for scraping metrics using Prometheus Operator | `false` | +| `metrics.serviceMonitor.namespace` | Namespace which Prometheus is running in | `""` | +| `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` | MetricsRelabelConfigs to apply to samples before ingestion. | `[]` | +| `metrics.serviceMonitor.labels` | Used to pass Labels that are used by the Prometheus installed in your cluster to select Service Monitors to work with | `{}` | +| `metrics.serviceMonitor.selector` | Prometheus instance selector labels | `{}` | +| `metrics.serviceMonitor.honorLabels` | Specify honorLabels parameter to add the scrape endpoint | `false` | +| `metrics.serviceMonitor.jobLabel` | The name of the label on the target service to use as the job name in prometheus. | `""` | +| `metrics.prometheusRule.enabled` | Set this to true to create prometheusRules for Prometheus operator | `false` | +| `metrics.prometheusRule.additionalLabels` | Additional labels that can be used so prometheusRules will be discovered by Prometheus | `{}` | +| `metrics.prometheusRule.namespace` | Namespace where prometheusRules resource should be created | `""` | +| `metrics.prometheusRule.rules` | Rules to be created, check values for an example | `[]` | + + +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.username=my-user,auth.password=my-password,auth.database=my-database \ + my-repo/mongodb +``` + +The above command sets the MongoDB(®) `root` account password to `secretpassword`. Additionally, it creates a standard database user named `my-user`, with the password `my-password`, who has access to 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/mongodb +``` + +> **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. + +### Customize a new MongoDB instance + +The [Bitnami MongoDB(®) image](https://github.com/bitnami/containers/tree/main/bitnami/mongodb) supports the use of custom scripts to initialize a fresh instance. In order to execute the scripts, two options are available: + +* Specify them using the `initdbScripts` parameter as dict. +* Define an external Kubernetes ConfigMap with all the initialization scripts by setting the `initdbScriptsConfigMap` parameter. Note that this will override the previous option. + +The allowed script extensions are `.sh` and `.js`. + +### Replicaset: Access MongoDB(®) nodes from outside the cluster + +In order to access MongoDB(®) nodes from outside the cluster when using a replicaset architecture, a specific service per MongoDB(®) pod will be created. There are two ways of configuring external access: + +- Using LoadBalancer services +- Using NodePort services. + +Refer to the [chart documentation for more details and configuration examples](https://docs.bitnami.com/kubernetes/infrastructure/mongodb/configuration/configure-external-access-replicaset/). + +### Add extra environment variables + +To add extra environment variables (useful for advanced operations like custom init scripts), use the `extraEnvVars` property. + +```yaml +extraEnvVars: + - name: LOG_LEVEL + value: error +``` + +Alternatively, you can use a ConfigMap or a Secret with the environment variables. To do so, use the `extraEnvVarsCM` or the `extraEnvVarsSecret` properties. + +### Use Sidecars and Init Containers + +If additional containers are needed in the same pod (such as additional metrics or logging exporters), they can be defined using the `sidecars` config parameter. Similarly, extra init containers can be added using the `initContainers` parameter. + +Refer to the chart documentation for more information on, and examples of, configuring and using [sidecars and init containers](https://docs.bitnami.com/kubernetes/infrastructure/mongodb/configuration/configure-sidecar-init-containers/). + +## Persistence + +The [Bitnami MongoDB(®)](https://github.com/bitnami/containers/tree/main/bitnami/mongodb) image stores the MongoDB(®) data and configurations at the `/bitnami/mongodb` path of the container. + +The chart mounts a [Persistent Volume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) at this location. The volume is created using dynamic volume provisioning. + +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/). + +## Use custom Prometheus rules + +Custom Prometheus rules can be defined for the Prometheus Operator by using the `prometheusRule` parameter. + +Refer to the [chart documentation for an example of a custom rule](https://docs.bitnami.com/kubernetes/infrastructure/mongodb/administration/use-prometheus-rules/). + +## Enable SSL/TLS + +This chart supports enabling SSL/TLS between nodes in the cluster, as well as between MongoDB(®) clients and nodes, by setting the `MONGODB_EXTRA_FLAGS` and `MONGODB_CLIENT_EXTRA_FLAGS` container environment variables, together with the correct `MONGODB_ADVERTISED_HOSTNAME`. To enable full TLS encryption, set the `tls.enabled` parameter to `true`. + +Refer to the [chart documentation for more information on enabling TLS](https://docs.bitnami.com/kubernetes/infrastructure/mongodb/administration/enable-tls/). + +### Set Pod affinity + +This chart allows you to set your custom affinity using the `XXX.affinity` parameter(s). Find more information about Pod affinity in the [Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity). + +As an alternative, you can use the preset configurations for pod affinity, pod anti-affinity, and node affinity available at the [bitnami/common](https://github.com/bitnami/charts/tree/main/bitnami/common#affinities) chart. To do so, set the `XXX.podAffinityPreset`, `XXX.podAntiAffinityPreset`, or `XXX.nodeAffinityPreset` parameters. + +## 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 + +If authentication is enabled, it's necessary to set the `auth.rootPassword` (also `auth.replicaSetKey` when using a replicaset architecture) 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 'Credentials' section. Please note down the password, and run the command below to upgrade your chart: + +```bash +$ helm upgrade my-release my-repo/mongodb --set auth.rootPassword=[PASSWORD] (--set auth.replicaSetKey=[REPLICASETKEY]) +``` + +> Note: you need to substitute the placeholders [PASSWORD] and [REPLICASETKEY] with the values obtained in the installation notes. + +### To 12.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: + +- `strategyType` is replaced by `updateStrategy` +- `service.port` is renamed to `service.ports.mongodb` +- `service.nodePort` is renamed to `service.nodePorts.mongodb` +- `externalAccess.service.port` is renamed to `externalAccess.hidden.service.ports.mongodb` +- `rbac.role.rules` is renamed to `rbac.rules` +- `externalAccess.hidden.service.port` is renamed ot `externalAccess.hidden.service.ports.mongodb` +- `hidden.strategyType` is replaced by `hidden.updateStrategy` +- `metrics.serviceMonitor.relabellings` is renamed to `metrics.serviceMonitor.relabelings`(typo fixed) +- `metrics.serviceMonitor.additionalLabels` is renamed to `metrics.serviceMonitor.labels` + +Additionally also updates the MongoDB image dependency to it newest major, 5.0 + +### To 11.0.0 + +In this version, the mongodb-exporter bundled as part of this Helm chart was updated to a new version which, even it is not a major change, can contain breaking changes (from `0.11.X` to `0.30.X`). +Please visit the release notes from the upstream project at https://github.com/percona/mongodb_exporter/releases + +### To 10.0.0 + +[On November 13, 2020, Helm v2 support formally ended](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/mongodb/administration/upgrade-helm3/). + +### To 9.0.0 + +MongoDB(®) container images were updated to `4.4.x` and it can affect compatibility with older versions of MongoDB(®). Refer to the following guides to upgrade your applications: + +- [Standalone](https://docs.mongodb.com/manual/release-notes/4.4-upgrade-standalone/) +- [Replica Set](https://docs.mongodb.com/manual/release-notes/4.4-upgrade-replica-set/) + +### To 8.0.0 + +- Architecture used to configure MongoDB(®) as a replicaset was completely refactored. Now, both primary and secondary nodes are part of the same statefulset. +- Chart labels were adapted to follow the Helm charts best practices. +- This version 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. +- Several parameters were renamed or disappeared in favor of new ones on this major version. These are the most important ones: + - `replicas` is renamed to `replicaCount`. + - Authentication parameters are reorganized under the `auth.*` parameter: + - `usePassword` is renamed to `auth.enabled`. + - `mongodbRootPassword`, `mongodbUsername`, `mongodbPassword`, `mongodbDatabase`, and `replicaSet.key` are now `auth.rootPassword`, `auth.username`, `auth.password`, `auth.database`, and `auth.replicaSetKey` respectively. + - `securityContext.*` is deprecated in favor of `podSecurityContext` and `containerSecurityContext`. + - Parameters prefixed with `mongodb` are renamed removing the prefix. E.g. `mongodbEnableIPv6` is renamed to `enableIPv6`. + - Parameters affecting Arbiter nodes are reorganized under the `arbiter.*` parameter. + +Consequences: + +- Backwards compatibility is not guaranteed. To upgrade to `8.0.0`, install a new release of the MongoDB(®) chart, and migrate your data by creating a backup of the database, and restoring it on the new release. + +### To 7.0.0 + +From this version, the way of setting the ingress rules has changed. Instead of using `ingress.paths` and `ingress.hosts` as separate objects, you should now define the rules as objects inside the `ingress.hosts` value, for example: + +```yaml +ingress: + hosts: + - name: mongodb.local + path: / +``` + +### To 6.0.0 + +From this version, `mongodbEnableIPv6` is set to `false` by default in order to work properly in most k8s clusters, if you want to use IPv6 support, you need to set this variable to `true` by adding `--set mongodbEnableIPv6=true` to your `helm` command. +You can find more information in the [`bitnami/mongodb` image README](https://github.com/bitnami/containers/tree/main/bitnami/mongodb#readme). + +### To 5.0.0 + +When enabling replicaset configuration, backwards compatibility is not guaranteed unless you modify the labels used on the chart's statefulsets. +Use the workaround below to upgrade from versions previous to 5.0.0. The following example assumes that the release name is `my-release`: + +```console +$ kubectl delete statefulset my-release-mongodb-arbiter my-release-mongodb-primary my-release-mongodb-secondary --cascade=false +``` + +### Add extra deployment options + +To add extra deployments (useful for advanced features like sidecars), use the `extraDeploy` property. + +In the example below, you can find how to use a example here for a [MongoDB replica set pod labeler sidecar](https://github.com/combor/k8s-mongo-labeler-sidecar) to identify the primary pod and dynamically label it as the primary node: + +```yaml +extraDeploy: + - apiVersion: v1 + kind: Service + metadata: + name: mongodb-primary + namespace: default + labels: + app.kubernetes.io/component: mongodb + app.kubernetes.io/instance: mongodb + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: mongodb + spec: + type: NodePort + externalTrafficPolicy: Cluster + ports: + - name: mongodb-primary + port: 30001 + nodePort: 30001 + protocol: TCP + targetPort: mongodb + selector: + app.kubernetes.io/component: mongodb + app.kubernetes.io/instance: mongodb + app.kubernetes.io/name: mongodb + primary: "true" +``` + +## 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/deployment/deployment/nginx-ingress-controller/charts/common/.helmignore b/deployment/charts/mongodb/charts/common/.helmignore similarity index 100% rename from deployment/deployment/nginx-ingress-controller/charts/common/.helmignore rename to deployment/charts/mongodb/charts/common/.helmignore diff --git a/deployment/charts/mongodb/charts/common/Chart.yaml b/deployment/charts/mongodb/charts/common/Chart.yaml new file mode 100644 index 0000000..f9ba944 --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/README.md b/deployment/charts/mongodb/charts/common/README.md new file mode 100644 index 0000000..ec43a5f --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/_affinities.tpl b/deployment/charts/mongodb/charts/common/templates/_affinities.tpl new file mode 100644 index 0000000..81902a6 --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/_capabilities.tpl b/deployment/charts/mongodb/charts/common/templates/_capabilities.tpl new file mode 100644 index 0000000..9d9b760 --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/_errors.tpl b/deployment/charts/mongodb/charts/common/templates/_errors.tpl new file mode 100644 index 0000000..a79cc2e --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/_images.tpl b/deployment/charts/mongodb/charts/common/templates/_images.tpl new file mode 100644 index 0000000..46c659e --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/_ingress.tpl b/deployment/charts/mongodb/charts/common/templates/_ingress.tpl new file mode 100644 index 0000000..831da9c --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/_labels.tpl b/deployment/charts/mongodb/charts/common/templates/_labels.tpl new file mode 100644 index 0000000..252066c --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/_names.tpl b/deployment/charts/mongodb/charts/common/templates/_names.tpl new file mode 100644 index 0000000..617a234 --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/_secrets.tpl b/deployment/charts/mongodb/charts/common/templates/_secrets.tpl new file mode 100644 index 0000000..a1708b2 --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/_storage.tpl b/deployment/charts/mongodb/charts/common/templates/_storage.tpl new file mode 100644 index 0000000..60e2a84 --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/_tplvalues.tpl b/deployment/charts/mongodb/charts/common/templates/_tplvalues.tpl new file mode 100644 index 0000000..2db1668 --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/_utils.tpl b/deployment/charts/mongodb/charts/common/templates/_utils.tpl new file mode 100644 index 0000000..b1ead50 --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/_warnings.tpl b/deployment/charts/mongodb/charts/common/templates/_warnings.tpl new file mode 100644 index 0000000..ae10fa4 --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/validations/_cassandra.tpl b/deployment/charts/mongodb/charts/common/templates/validations/_cassandra.tpl new file mode 100644 index 0000000..ded1ae3 --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/validations/_mariadb.tpl b/deployment/charts/mongodb/charts/common/templates/validations/_mariadb.tpl new file mode 100644 index 0000000..b6906ff --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/validations/_mongodb.tpl b/deployment/charts/mongodb/charts/common/templates/validations/_mongodb.tpl new file mode 100644 index 0000000..f820ec1 --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/validations/_mysql.tpl b/deployment/charts/mongodb/charts/common/templates/validations/_mysql.tpl new file mode 100644 index 0000000..74472a0 --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/validations/_postgresql.tpl b/deployment/charts/mongodb/charts/common/templates/validations/_postgresql.tpl new file mode 100644 index 0000000..164ec0d --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/validations/_redis.tpl b/deployment/charts/mongodb/charts/common/templates/validations/_redis.tpl new file mode 100644 index 0000000..dcccfc1 --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/templates/validations/_validations.tpl b/deployment/charts/mongodb/charts/common/templates/validations/_validations.tpl new file mode 100644 index 0000000..9a814cf --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/charts/common/values.yaml b/deployment/charts/mongodb/charts/common/values.yaml new file mode 100644 index 0000000..f2df68e --- /dev/null +++ b/deployment/charts/mongodb/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/deployment/charts/mongodb/templates/NOTES.txt b/deployment/charts/mongodb/templates/NOTES.txt new file mode 100644 index 0000000..f587cdd --- /dev/null +++ b/deployment/charts/mongodb/templates/NOTES.txt @@ -0,0 +1,202 @@ +CHART NAME: {{ .Chart.Name }} +CHART VERSION: {{ .Chart.Version }} +APP VERSION: {{ .Chart.AppVersion }} + +{{- 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/mongodb/entrypoint.sh /opt/bitnami/scripts/mongodb/run.sh + +{{- else }} + +{{- $replicaCount := int .Values.replicaCount }} +{{- $portNumber := int .Values.service.ports.mongodb }} +{{- $fullname := include "mongodb.fullname" . }} +{{- $releaseNamespace := include "mongodb.namespace" . }} +{{- $clusterDomain := .Values.clusterDomain }} +{{- $loadBalancerIPListLength := len .Values.externalAccess.service.loadBalancerIPs }} +{{- $mongoList := list }} +{{- range $e, $i := until $replicaCount }} +{{- $mongoList = append $mongoList (printf "%s-%d.%s-headless.%s.svc.%s:%d" $fullname $i $fullname $releaseNamespace $clusterDomain $portNumber) }} +{{- end }} + +{{- if and (eq .Values.architecture "replicaset") .Values.externalAccess.enabled (not .Values.externalAccess.autoDiscovery.enabled) (not (eq $replicaCount $loadBalancerIPListLength )) (eq .Values.externalAccess.service.type "LoadBalancer") }} + +#################################################################################### +### ERROR: You enabled external access to MongoDB® nodes without specifying ### +### the array of load balancer IPs for MongoDB® nodes. ### +#################################################################################### + +This deployment will be incomplete until you configure the array of load balancer +IPs for MongoDB® nodes. To complete your deployment follow the steps below: + +1. Wait for the load balancer IPs (it may take a few minutes for them to be available): + + kubectl get svc --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ template "mongodb.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=mongodb" -w + +2. Obtain the load balancer IPs and upgrade your chart: + + {{- range $e, $i := until $replicaCount }} + LOAD_BALANCER_IP_{{ add $i 1 }}="$(kubectl get svc --namespace {{ $releaseNamespace }} {{ $fullname }}-{{ $i }}-external -o jsonpath='{.status.loadBalancer.ingress[0].ip}')" + {{- end }} + +3. Upgrade you chart: + + helm upgrade --namespace {{ .Release.Namespace }} {{ .Release.Name }} my-repo/{{ .Chart.Name }} \ + --set mongodb.replicaCount={{ $replicaCount }} \ + --set mongodb.externalAccess.enabled=true \ + {{- range $i, $e := until $replicaCount }} + --set mongodb.externalAccess.service.loadBalancerIPs[{{ $i }}]=$LOAD_BALANCER_IP_{{ add $i 1 }} \ + {{- end }} + --set mongodb.externalAccess.service.type=LoadBalancer + +{{- else }} + +{{- if and (or (and (eq .Values.architecture "standalone") (or (eq .Values.service.type "LoadBalancer") (eq .Values.service.type "NodePort"))) (and (eq .Values.architecture "replicaset") .Values.externalAccess.enabled)) (not .Values.auth.enabled) }} +------------------------------------------------------------------------------- + WARNING + + By not enabling "mongodb.auth.enabled" you have most likely exposed the + MongoDB® service externally without any authentication mechanism. + + For security reasons, we strongly suggest that you enable authentiation + setting the "mongodb.auth.enabled" parameter to "true". + +------------------------------------------------------------------------------- +{{- end }} + +** Please be patient while the chart is being deployed ** + +MongoDB® can be accessed on the following DNS name(s) and ports from within your cluster: + +{{- if eq .Values.architecture "replicaset" }} +{{ join "\n" $mongoList | nindent 4 }} +{{- else }} + + {{ $fullname }}.{{ $releaseNamespace }}.svc.{{ .Values.clusterDomain }} + +{{- end }} + +{{- if .Values.auth.enabled }} + +To get the root password run: + + export MONGODB_ROOT_PASSWORD=$(kubectl get secret --namespace {{ template "mongodb.namespace" . }} {{ template "mongodb.secretName" . }} -o jsonpath="{.data.mongodb-root-password}" | base64 -d) + +{{- end }} +{{- $customUsers := include "mongodb.customUsers" . -}} +{{- $customDatabases := include "mongodb.customDatabases" . -}} +{{- if and (not (empty $customUsers)) (not (empty $customDatabases)) }} +{{- $customUsersList := splitList "," $customUsers }} +{{- range $index, $user := $customUsersList }} + +To get the password for "{{ $user }}" run: + + export MONGODB_PASSWORD=$(kubectl get secret --namespace {{ include "mongodb.namespace" $ }} {{ include "mongodb.secretName" $ }} -o jsonpath="{.data.mongodb-passwords}" | base64 -d | awk -F',' '{print ${{ add 1 $index }}}') + +{{- end }} +{{- end }} + +To connect to your database, create a MongoDB® client container: + + kubectl run --namespace {{ template "mongodb.namespace" . }} {{ template "mongodb.fullname" . }}-client --rm --tty -i --restart='Never' --env="MONGODB_ROOT_PASSWORD=$MONGODB_ROOT_PASSWORD" --image {{ template "mongodb.image" . }} --command -- bash + +Then, run the following command: + + {{- if eq .Values.architecture "replicaset" }} + mongosh admin --host "{{ join "," $mongoList }}" {{- if .Values.auth.enabled }} --authenticationDatabase admin -u root -p $MONGODB_ROOT_PASSWORD{{- end }} + {{- else }} + mongosh admin --host "{{ template "mongodb.fullname" . }}" {{- if .Values.auth.enabled }} --authenticationDatabase admin -u root -p $MONGODB_ROOT_PASSWORD{{- end }} + {{- end }} + +{{- if and (eq .Values.architecture "replicaset") .Values.externalAccess.enabled }} + +To connect to your database nodes from outside, you need to add both primary and secondary nodes hostnames/IPs to your Mongo client. To obtain them, follow the instructions below: + +{{- if eq "NodePort" .Values.externalAccess.service.type }} +{{- if .Values.externalAccess.service.domain }} + + MongoDB® nodes domain: Use your provided hostname to reach MongoDB® nodes, {{ .Values.externalAccess.service.domain }} + +{{- else }} + + MongoDB® nodes domain: you can reach MongoDB® nodes on any of the K8s nodes external IPs. + + kubectl get nodes -o wide + +{{- end }} + + MongoDB® nodes port: You will have a different node port for each MongoDB® node. You can get the list of configured node ports using the command below: + + echo "$(kubectl get svc --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ template "mongodb.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=mongodb,pod" -o jsonpath='{.items[*].spec.ports[0].nodePort}' | tr ' ' '\n')" + +{{- else if contains "LoadBalancer" .Values.externalAccess.service.type }} + + NOTE: It may take a few minutes for the LoadBalancer IPs to be available. + Watch the status with: 'kubectl get svc --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ template "mongodb.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=mongodb,pod" -w' + + MongoDB® nodes domain: You will have a different external IP for each MongoDB® node. You can get the list of external IPs using the command below: + + echo "$(kubectl get svc --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ template "mongodb.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=mongodb,pod" -o jsonpath='{.items[*].status.loadBalancer.ingress[0].ip}' | tr ' ' '\n')" + + MongoDB® nodes port: {{ .Values.externalAccess.service.ports.mongodb }} + +{{- end }} + +{{- else if eq .Values.architecture "standalone" }} + +To connect to your database from outside the cluster execute the following commands: + +{{- if contains "NodePort" .Values.service.type }} + + export NODE_IP=$(kubectl get nodes --namespace {{ template "mongodb.namespace" . }} -o jsonpath="{.items[0].status.addresses[0].address}") + export NODE_PORT=$(kubectl get --namespace {{ template "mongodb.namespace" . }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "mongodb.fullname" . }}) + mongo --host $NODE_IP --port $NODE_PORT {{- if .Values.auth.enabled }} --authenticationDatabase admin -p $MONGODB_ROOT_PASSWORD{{- end }} + +{{- else if contains "LoadBalancer" .Values.service.type }} + + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + Watch the status with: 'kubectl get svc --namespace {{ template "mongodb.namespace" . }} -w {{ template "mongodb.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ template "mongodb.namespace" . }} {{ template "mongodb.fullname" . }} --template "{{ "{{ range (index .status.loadBalancer.ingress 0) }}{{ . }}{{ end }}" }}") + mongosh --host $SERVICE_IP --port {{ $portNumber }} {{- if .Values.auth.enabled }} --authenticationDatabase admin -p $MONGODB_ROOT_PASSWORD{{- end }} + +{{- else if contains "ClusterIP" .Values.service.type }} + + kubectl port-forward --namespace {{ template "mongodb.namespace" . }} svc/{{ template "mongodb.fullname" . }} {{ $portNumber }}:{{ $portNumber }} & + mongosh --host 127.0.0.1 {{- if .Values.auth.enabled }} --authenticationDatabase admin -p $MONGODB_ROOT_PASSWORD{{- end }} + +{{- end }} +{{- end }} +{{- end }} + +{{- if .Values.metrics.enabled }} + +To access the MongoDB® Prometheus metrics, get the MongoDB® Prometheus URL by running: + + kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ include "mongodb.fullname" . }}-metrics {{ .Values.metrics.service.ports.metrics }}:{{ .Values.metrics.service.ports.metrics }} & + echo "Prometheus Metrics URL: http://127.0.0.1:{{ .Values.metrics.service.ports.metrics }}/metrics" + +Then, open the obtained URL in a browser. + +{{- end }} +{{- end }} +{{- include "common.warnings.rollingTag" .Values.image }} +{{- include "common.warnings.rollingTag" .Values.metrics.image }} +{{- include "common.warnings.rollingTag" .Values.externalAccess.autoDiscovery.image }} +{{- include "common.warnings.rollingTag" .Values.volumePermissions.image }} +{{- include "common.warnings.rollingTag" .Values.tls.image }} +{{- include "mongodb.validateValues" . }} diff --git a/deployment/charts/mongodb/templates/_helpers.tpl b/deployment/charts/mongodb/templates/_helpers.tpl new file mode 100644 index 0000000..46aaf2f --- /dev/null +++ b/deployment/charts/mongodb/templates/_helpers.tpl @@ -0,0 +1,472 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "mongodb.name" -}} +{{- include "common.names.name" . -}} +{{- 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 "mongodb.fullname" -}} +{{- include "common.names.fullname" . -}} +{{- end -}} + +{{/* +Create a default mongo service name which can be overridden. +*/}} +{{- define "mongodb.service.nameOverride" -}} + {{- if and .Values.service .Values.service.nameOverride -}} + {{- print .Values.service.nameOverride -}} + {{- else -}} + {{- printf "%s-headless" (include "mongodb.fullname" .) -}} + {{- end }} +{{- end }} + +{{/* +Create a default mongo arbiter service name which can be overridden. +*/}} +{{- define "mongodb.arbiter.service.nameOverride" -}} + {{- if and .Values.arbiter.service .Values.arbiter.service.nameOverride -}} + {{- print .Values.arbiter.service.nameOverride -}} + {{- else -}} + {{- printf "%s-arbiter-headless" (include "mongodb.fullname" .) -}} + {{- end }} +{{- end }} + +{{/* +Return the proper MongoDB® image name +*/}} +{{- define "mongodb.image" -}} +{{- include "common.images.image" (dict "imageRoot" .Values.image "global" .Values.global) -}} +{{- end -}} + +{{/* +Return the proper image name (for the metrics image) +*/}} +{{- define "mongodb.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 "mongodb.volumePermissions.image" -}} +{{- include "common.images.image" (dict "imageRoot" .Values.volumePermissions.image "global" .Values.global) -}} +{{- end -}} + +{{/* +Return the proper image name (for the init container auto-discovery image) +*/}} +{{- define "mongodb.externalAccess.autoDiscovery.image" -}} +{{- include "common.images.image" (dict "imageRoot" .Values.externalAccess.autoDiscovery.image "global" .Values.global) -}} +{{- end -}} + +{{/* +Return the proper image name (for the TLS Certs image) +*/}} +{{- define "mongodb.tls.image" -}} +{{- include "common.images.image" (dict "imageRoot" .Values.tls.image "global" .Values.global) -}} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names +*/}} +{{- define "mongodb.imagePullSecrets" -}} +{{- include "common.images.pullSecrets" (dict "images" (list .Values.image .Values.metrics.image .Values.volumePermissions.image .Values.tls.image) "global" .Values.global) -}} +{{- end -}} + +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts. +*/}} +{{- define "mongodb.namespace" -}} + {{- if and .Values.global .Values.global.namespaceOverride -}} + {{- print .Values.global.namespaceOverride -}} + {{- else -}} + {{- print .Release.Namespace -}} + {{- end }} +{{- end -}} +{{- define "mongodb.serviceMonitor.namespace" -}} + {{- if .Values.metrics.serviceMonitor.namespace -}} + {{- print .Values.metrics.serviceMonitor.namespace -}} + {{- else -}} + {{- include "mongodb.namespace" . -}} + {{- end }} +{{- end -}} +{{- define "mongodb.prometheusRule.namespace" -}} + {{- if .Values.metrics.prometheusRule.namespace -}} + {{- print .Values.metrics.prometheusRule.namespace -}} + {{- else -}} + {{- include "mongodb.namespace" . -}} + {{- end }} +{{- end -}} + +{{/* +Returns the proper service account name depending if an explicit service account name is set +in the values file. If the name is not set it will default to either mongodb.fullname if serviceAccount.create +is true or default otherwise. +*/}} +{{- define "mongodb.serviceAccountName" -}} + {{- if .Values.serviceAccount.create -}} + {{- default (include "mongodb.fullname" .) (print .Values.serviceAccount.name) -}} + {{- else -}} + {{- default "default" (print .Values.serviceAccount.name) -}} + {{- end -}} +{{- end -}} + +{{/* +Return the list of custom users to create during the initialization (string format) +*/}} +{{- define "mongodb.customUsers" -}} + {{- $customUsers := list -}} + {{- if .Values.auth.username -}} + {{- $customUsers = append $customUsers .Values.auth.username }} + {{- end }} + {{- range .Values.auth.usernames }} + {{- $customUsers = append $customUsers . }} + {{- end }} + {{- printf "%s" (default "" (join "," $customUsers)) -}} +{{- end -}} + +{{/* +Return the list of passwords for the custom users (string format) +*/}} +{{- define "mongodb.customPasswords" -}} + {{- $customPasswords := list -}} + {{- if .Values.auth.password -}} + {{- $customPasswords = append $customPasswords .Values.auth.password }} + {{- end }} + {{- range .Values.auth.passwords }} + {{- $customPasswords = append $customPasswords . }} + {{- end }} + {{- printf "%s" (default "" (join "," $customPasswords)) -}} +{{- end -}} + +{{/* +Return the list of custom databases to create during the initialization (string format) +*/}} +{{- define "mongodb.customDatabases" -}} + {{- $customDatabases := list -}} + {{- if .Values.auth.database -}} + {{- $customDatabases = append $customDatabases .Values.auth.database }} + {{- end }} + {{- range .Values.auth.databases }} + {{- $customDatabases = append $customDatabases . }} + {{- end }} + {{- printf "%s" (default "" (join "," $customDatabases)) -}} +{{- end -}} + +{{/* +Return the configmap with the MongoDB® configuration +*/}} +{{- define "mongodb.configmapName" -}} +{{- if .Values.existingConfigmap -}} + {{- printf "%s" (tpl .Values.existingConfigmap $) -}} +{{- else -}} + {{- printf "%s" (include "mongodb.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a configmap object should be created for MongoDB® +*/}} +{{- define "mongodb.createConfigmap" -}} +{{- if and .Values.configuration (not .Values.existingConfigmap) }} + {{- true -}} +{{- else -}} +{{- end -}} +{{- end -}} + +{{/* +Return the secret with MongoDB® credentials +*/}} +{{- define "mongodb.secretName" -}} + {{- if .Values.auth.existingSecret -}} + {{- printf "%s" (tpl .Values.auth.existingSecret $) -}} + {{- else -}} + {{- printf "%s" (include "mongodb.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{/* +Return true if a secret object should be created for MongoDB® +*/}} +{{- define "mongodb.createSecret" -}} +{{- if and .Values.auth.enabled (not .Values.auth.existingSecret) }} + {{- true -}} +{{- else -}} +{{- end -}} +{{- end -}} + +{{/* +Get the initialization scripts ConfigMap name. +*/}} +{{- define "mongodb.initdbScriptsCM" -}} +{{- if .Values.initdbScriptsConfigMap -}} +{{- printf "%s" .Values.initdbScriptsConfigMap -}} +{{- else -}} +{{- printf "%s-init-scripts" (include "mongodb.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if the Arbiter should be deployed +*/}} +{{- define "mongodb.arbiter.enabled" -}} +{{- if and (eq .Values.architecture "replicaset") .Values.arbiter.enabled }} + {{- true -}} +{{- else -}} +{{- end -}} +{{- end -}} + +{{/* +Return the configmap with the MongoDB® configuration for the Arbiter +*/}} +{{- define "mongodb.arbiter.configmapName" -}} +{{- if .Values.arbiter.existingConfigmap -}} + {{- printf "%s" (tpl .Values.arbiter.existingConfigmap $) -}} +{{- else -}} + {{- printf "%s-arbiter" (include "mongodb.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a configmap object should be created for MongoDB® Arbiter +*/}} +{{- define "mongodb.arbiter.createConfigmap" -}} +{{- if and (eq .Values.architecture "replicaset") .Values.arbiter.enabled .Values.arbiter.configuration (not .Values.arbiter.existingConfigmap) }} + {{- true -}} +{{- else -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if the Hidden should be deployed +*/}} +{{- define "mongodb.hidden.enabled" -}} +{{- if and (eq .Values.architecture "replicaset") .Values.hidden.enabled }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return the configmap with the MongoDB® configuration for the Hidden +*/}} +{{- define "mongodb.hidden.configmapName" -}} +{{- if .Values.hidden.existingConfigmap -}} + {{- printf "%s" (tpl .Values.hidden.existingConfigmap $) -}} +{{- else -}} + {{- printf "%s-hidden" (include "mongodb.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a configmap object should be created for MongoDB® Hidden +*/}} +{{- define "mongodb.hidden.createConfigmap" -}} +{{- if and (include "mongodb.hidden.enabled" .) .Values.hidden.enabled .Values.hidden.configuration (not .Values.hidden.existingConfigmap) }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Compile all warnings into a single message, and call fail. +*/}} +{{- define "mongodb.validateValues" -}} +{{- $messages := list -}} +{{- $messages := append $messages (include "mongodb.validateValues.pspAndRBAC" .) -}} +{{- $messages := append $messages (include "mongodb.validateValues.architecture" .) -}} +{{- $messages := append $messages (include "mongodb.validateValues.customUsersDBs" .) -}} +{{- $messages := append $messages (include "mongodb.validateValues.customUsersDBsLength" .) -}} +{{- $messages := append $messages (include "mongodb.validateValues.externalAccessServiceType" .) -}} +{{- $messages := append $messages (include "mongodb.validateValues.loadBalancerIPsListLength" .) -}} +{{- $messages := append $messages (include "mongodb.validateValues.nodePortListLength" .) -}} +{{- $messages := append $messages (include "mongodb.validateValues.externalAccessAutoDiscoveryRBAC" .) -}} +{{- $messages := append $messages (include "mongodb.validateValues.replicaset.existingSecrets" .) -}} +{{- $messages := append $messages (include "mongodb.validateValues.hidden.existingSecrets" .) -}} +{{- $messages := without $messages "" -}} +{{- $message := join "\n" $messages -}} + +{{- if $message -}} +{{- printf "\nVALUES VALIDATION:\n%s" $message | fail -}} +{{- end -}} +{{- end -}} + +{{/* Validate RBAC is created when using PSP */}} +{{- define "mongodb.validateValues.pspAndRBAC" -}} +{{- if and (.Values.podSecurityPolicy.create) (not .Values.rbac.create) -}} +mongodb: podSecurityPolicy.create, rbac.create + Both podSecurityPolicy.create and rbac.create must be true, if you want + to create podSecurityPolicy +{{- end -}} +{{- end -}} + +{{/* Validate values of MongoDB® - must provide a valid architecture */}} +{{- define "mongodb.validateValues.architecture" -}} +{{- if and (ne .Values.architecture "standalone") (ne .Values.architecture "replicaset") -}} +mongodb: architecture + Invalid architecture selected. Valid values are "standalone" and + "replicaset". Please set a valid architecture (--set mongodb.architecture="xxxx") +{{- end -}} +{{- end -}} + +{{/* +Validate values of MongoDB® - both auth.usernames and auth.databases are necessary +to create a custom user and database during 1st initialization +*/}} +{{- define "mongodb.validateValues.customUsersDBs" -}} +{{- $customUsers := include "mongodb.customUsers" . -}} +{{- $customDatabases := include "mongodb.customDatabases" . -}} +{{- if or (and (empty $customUsers) (not (empty $customDatabases))) (and (not (empty $customUsers)) (empty $customDatabases)) }} +mongodb: auth.usernames, auth.databases + Both auth.usernames and auth.databases must be provided to create + custom users and databases during 1st initialization. + Please set both of them (--set auth.usernames[0]="xxxx",auth.databases[0]="yyyy") +{{- end -}} +{{- end -}} + +{{/* +Validate values of MongoDB® - both auth.usernames and auth.databases arrays should have the same length +to create a custom user and database during 1st initialization +*/}} +{{- define "mongodb.validateValues.customUsersDBsLength" -}} +{{- if ne (len .Values.auth.usernames) (len .Values.auth.databases) }} +mongodb: auth.usernames, auth.databases + Both auth.usernames and auth.databases arrays should have the same length +{{- end -}} +{{- end -}} + +{{/* +Validate values of MongoDB® - service type for external access +*/}} +{{- define "mongodb.validateValues.externalAccessServiceType" -}} +{{- if and (eq .Values.architecture "replicaset") (not (eq .Values.externalAccess.service.type "NodePort")) (not (eq .Values.externalAccess.service.type "LoadBalancer")) (not (eq .Values.externalAccess.service.type "ClusterIP")) -}} +mongodb: externalAccess.service.type + Available service type for external access are NodePort, LoadBalancer or ClusterIP. +{{- end -}} +{{- end -}} + +{{/* +Validate values of MongoDB® - number of replicas must be the same than LoadBalancer IPs list +*/}} +{{- define "mongodb.validateValues.loadBalancerIPsListLength" -}} +{{- $replicaCount := int .Values.replicaCount }} +{{- $loadBalancerListLength := len .Values.externalAccess.service.loadBalancerIPs }} +{{- if and (eq .Values.architecture "replicaset") .Values.externalAccess.enabled (not .Values.externalAccess.autoDiscovery.enabled ) (eq .Values.externalAccess.service.type "LoadBalancer") (not (eq $replicaCount $loadBalancerListLength )) -}} +mongodb: .Values.externalAccess.service.loadBalancerIPs + Number of replicas and loadBalancerIPs array length must be the same. +{{- end -}} +{{- end -}} + +{{/* +Validate values of MongoDB® - number of replicas must be the same than NodePort list +*/}} +{{- define "mongodb.validateValues.nodePortListLength" -}} +{{- $replicaCount := int .Values.replicaCount }} +{{- $nodePortListLength := len .Values.externalAccess.service.nodePorts }} +{{- if and (eq .Values.architecture "replicaset") .Values.externalAccess.enabled (eq .Values.externalAccess.service.type "NodePort") (not (eq $replicaCount $nodePortListLength )) -}} +mongodb: .Values.externalAccess.service.nodePorts + Number of replicas and nodePorts array length must be the same. +{{- end -}} +{{- end -}} + +{{/* +Validate values of MongoDB® - RBAC should be enabled when autoDiscovery is enabled +*/}} +{{- define "mongodb.validateValues.externalAccessAutoDiscoveryRBAC" -}} +{{- if and (eq .Values.architecture "replicaset") .Values.externalAccess.enabled .Values.externalAccess.autoDiscovery.enabled (not .Values.rbac.create ) }} +mongodb: rbac.create + By specifying "externalAccess.enabled=true" and "externalAccess.autoDiscovery.enabled=true" + an initContainer will be used to autodetect the external IPs/ports by querying the + K8s API. Please note this initContainer requires specific RBAC resources. You can create them + by specifying "--set rbac.create=true". +{{- end -}} +{{- end -}} + +{{/* +Validate values of MongoDB® - Number of replicaset secrets must be the same than number of replicaset nodes. +*/}} +{{- define "mongodb.validateValues.replicaset.existingSecrets" -}} +{{- if and .Values.tls.enabled (eq .Values.architecture "replicaset") (not (empty .Values.tls.replicaset.existingSecrets)) }} +{{- $nbSecrets := len .Values.tls.replicaset.existingSecrets -}} +{{- if not (eq $nbSecrets (int .Values.replicaCount)) }} +mongodb: tls.replicaset.existingSecrets + tls.replicaset.existingSecrets Number of secrets and number of replicaset nodes must be the same. +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Validate values of MongoDB® - Number of hidden secrets must be the same than number of hidden nodes. +*/}} +{{- define "mongodb.validateValues.hidden.existingSecrets" -}} +{{- if and .Values.tls.enabled (include "mongodb.hidden.enabled" .) (not (empty .Values.tls.hidden.existingSecrets)) }} +{{- $nbSecrets := len .Values.tls.hidden.existingSecrets -}} +{{- if not (eq $nbSecrets (int .Values.hidden.replicaCount)) }} +mongodb: tls.hidden.existingSecrets + tls.hidden.existingSecrets Number of secrets and number of hidden nodes must be the same. +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Validate values of MongoDB® exporter URI string - auth.enabled and/or tls.enabled must be enabled or it defaults +*/}} +{{- define "mongodb.mongodb_exporter.uri" -}} + {{- $uriTlsArgs := ternary "tls=true&tlsCertificateKeyFile=/certs/mongodb.pem&tlsCAFile=/certs/mongodb-ca-cert" "" .Values.tls.enabled -}} + {{- if .Values.metrics.username }} + {{- $uriAuth := ternary "$(echo $MONGODB_METRICS_USERNAME | sed -r \"s/@/%40/g;s/:/%3A/g\"):$(echo $MONGODB_METRICS_PASSWORD | sed -r \"s/@/%40/g;s/:/%3A/g\")@" "" .Values.auth.enabled -}} + {{- printf "mongodb://%slocalhost:%d/admin?%s" $uriAuth (int .Values.containerPorts.mongodb) $uriTlsArgs -}} + {{- else -}} + {{- $uriAuth := ternary "$MONGODB_ROOT_USER:$(echo $MONGODB_ROOT_PASSWORD | sed -r \"s/@/%40/g;s/:/%3A/g\")@" "" .Values.auth.enabled -}} + {{- printf "mongodb://%slocalhost:%d/admin?%s" $uriAuth (int .Values.containerPorts.mongodb) $uriTlsArgs -}} + {{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiGroup for PodSecurityPolicy. +*/}} +{{- define "podSecurityPolicy.apiGroup" -}} +{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "policy" -}} +{{- else -}} +{{- print "extensions" -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a TLS secret object should be created +*/}} +{{- define "mongodb.createTlsSecret" -}} +{{- if and .Values.tls.enabled (not .Values.tls.existingSecret) (include "mongodb.autoGenerateCerts" .) }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return the secret containing MongoDB® TLS certificates +*/}} +{{- define "mongodb.tlsSecretName" -}} +{{- $secretName := .Values.tls.existingSecret -}} +{{- if $secretName -}} + {{- printf "%s" (tpl $secretName $) -}} +{{- else -}} + {{- printf "%s-ca" (include "mongodb.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if certificates must be auto generated +*/}} +{{- define "mongodb.autoGenerateCerts" -}} +{{- $standalone := (eq .Values.architecture "standalone") | ternary (not .Values.tls.standalone.existingSecret) true -}} +{{- $replicaset := (eq .Values.architecture "replicaset") | ternary (empty .Values.tls.replicaset.existingSecrets) true -}} +{{- $arbiter := (eq (include "mongodb.arbiter.enabled" .) "true") | ternary (not .Values.tls.arbiter.existingSecret) true -}} +{{- $hidden := (eq (include "mongodb.hidden.enabled" .) "true") | ternary (empty .Values.tls.hidden.existingSecrets) true -}} +{{- if and $standalone $replicaset $arbiter $hidden -}} + {{- true -}} +{{- end -}} +{{- end -}} diff --git a/deployment/charts/mongodb/templates/arbiter/configmap.yaml b/deployment/charts/mongodb/templates/arbiter/configmap.yaml new file mode 100644 index 0000000..1aacbd7 --- /dev/null +++ b/deployment/charts/mongodb/templates/arbiter/configmap.yaml @@ -0,0 +1,18 @@ +{{- if (include "mongodb.arbiter.createConfigmap" .) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ print "%s-arbiter" (include "mongodb.fullname" .) }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: arbiter + {{- 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: + mongodb.conf: |- + {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.configuration "context" $) | nindent 4 }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/arbiter/headless-svc.yaml b/deployment/charts/mongodb/templates/arbiter/headless-svc.yaml new file mode 100644 index 0000000..2bc3658 --- /dev/null +++ b/deployment/charts/mongodb/templates/arbiter/headless-svc.yaml @@ -0,0 +1,33 @@ +{{- if (include "mongodb.arbiter.enabled" .) }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "mongodb.arbiter.service.nameOverride" . }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: arbiter + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if or .Values.arbiter.service.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.arbiter.service.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.arbiter.service.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: ClusterIP + clusterIP: None + ports: + - name: tcp-mongodb + port: {{ .Values.arbiter.service.ports.mongodb }} + targetPort: mongodb + {{- if .Values.arbiter.service.extraPorts }} + {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.service.extraPorts "context" $) | nindent 4 }} + {{- end }} + selector: {{- include "common.labels.matchLabels" . | nindent 4 }} + app.kubernetes.io/component: arbiter +{{- end }} diff --git a/deployment/charts/mongodb/templates/arbiter/pdb.yaml b/deployment/charts/mongodb/templates/arbiter/pdb.yaml new file mode 100644 index 0000000..6402f68 --- /dev/null +++ b/deployment/charts/mongodb/templates/arbiter/pdb.yaml @@ -0,0 +1,25 @@ +{{- if and (include "mongodb.arbiter.enabled" .) .Values.arbiter.pdb.create }} +apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ printf "%s-arbiter" (include "mongodb.fullname" .) }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: arbiter + {{- 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.arbiter.pdb.minAvailable }} + minAvailable: {{ .Values.arbiter.pdb.minAvailable }} + {{- end }} + {{- if .Values.arbiter.pdb.maxUnavailable }} + maxUnavailable: {{ .Values.arbiter.pdb.maxUnavailable }} + {{- end }} + selector: + matchLabels: {{ include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: arbiter +{{- end }} diff --git a/deployment/charts/mongodb/templates/arbiter/statefulset.yaml b/deployment/charts/mongodb/templates/arbiter/statefulset.yaml new file mode 100644 index 0000000..dbe42ff --- /dev/null +++ b/deployment/charts/mongodb/templates/arbiter/statefulset.yaml @@ -0,0 +1,298 @@ +{{- if (include "mongodb.arbiter.enabled" .) }} +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ printf "%s-arbiter" (include "mongodb.fullname" .) }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: arbiter + {{- if .Values.arbiter.labels }} + {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.labels "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if or .Values.arbiter.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.arbiter.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.arbiter.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + serviceName: {{ include "mongodb.arbiter.service.nameOverride" . }} + podManagementPolicy: {{ .Values.arbiter.podManagementPolicy }} + {{- if .Values.arbiter.updateStrategy }} + updateStrategy: {{- toYaml .Values.arbiter.updateStrategy | nindent 4 }} + {{- end }} + selector: + matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: arbiter + template: + metadata: + labels: {{- include "common.labels.standard" . | nindent 8 }} + app.kubernetes.io/component: arbiter + {{- if .Values.arbiter.podLabels }} + {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.podLabels "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 8 }} + {{- end }} + {{- if or (include "mongodb.arbiter.createConfigmap" .) .Values.arbiter.podAnnotations }} + annotations: + {{- if (include "mongodb.arbiter.createConfigmap" .) }} + checksum/configuration: {{ include (print $.Template.BasePath "/arbiter/configmap.yaml") . | sha256sum }} + {{- end }} + {{- if .Values.arbiter.podAnnotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.podAnnotations "context" $) | nindent 8 }} + {{- end }} + {{- end }} + spec: + {{- include "mongodb.imagePullSecrets" . | nindent 6 }} + {{- if .Values.arbiter.schedulerName }} + schedulerName: {{ .Values.arbiter.schedulerName | quote }} + {{- end }} + serviceAccountName: {{ template "mongodb.serviceAccountName" . }} + {{- if .Values.arbiter.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.arbiter.podAffinityPreset "component" "arbiter" "topologyKey" .Values.topologyKey "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.arbiter.podAntiAffinityPreset "component" "arbiter" "topologyKey" .Values.topologyKey "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.arbiter.nodeAffinityPreset.type "key" .Values.arbiter.nodeAffinityPreset.key "values" .Values.arbiter.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.arbiter.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.arbiter.hostAliases }} + hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.hostAliases "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.arbiter.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.tolerations "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.arbiter.topologySpreadConstraints }} + topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.topologySpreadConstraints "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.arbiter.priorityClassName }} + priorityClassName: {{ .Values.arbiter.priorityClassName }} + {{- end }} + {{- if .Values.arbiter.runtimeClassName }} + runtimeClassName: {{ .Values.arbiter.runtimeClassName }} + {{- end }} + {{- if .Values.arbiter.podSecurityContext.enabled }} + securityContext: {{- omit .Values.arbiter.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{ if .Values.arbiter.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.arbiter.terminationGracePeriodSeconds }} + {{- end }} + initContainers: + {{- if .Values.arbiter.initContainers }} + {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.initContainers "context" $) | nindent 8 }} + {{- end }} + {{- if and .Values.tls.enabled .Values.arbiter.enabled }} + - name: generate-tls-certs + image: {{ include "mongodb.tls.image" . }} + imagePullPolicy: {{ .Values.tls.image.pullPolicy | quote }} + env: + - name: MY_POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: MY_POD_HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + volumeMounts: + {{- if (include "mongodb.autoGenerateCerts" .) }} + - name: certs-volume + mountPath: /certs/CAs + {{- else }} + - name: mongodb-certs-0 + mountPath: /certs-0 + {{- end }} + - name: certs + mountPath: /certs + - name: common-scripts + mountPath: /bitnami/scripts + command: + - /bitnami/scripts/generate-certs.sh + args: + - -s {{ include "mongodb.arbiter.service.nameOverride" . }} + {{- end }} + containers: + - name: mongodb-arbiter + image: {{ include "mongodb.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy | quote }} + {{- if .Values.arbiter.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.arbiter.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.arbiter.command }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.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.arbiter.args }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.args "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.arbiter.lifecycleHooks }} + lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.lifecycleHooks "context" $) | nindent 12 }} + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" (or .Values.image.debug .Values.diagnosticMode.enabled) | quote }} + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: MY_POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: K8S_SERVICE_NAME + value: "{{ include "mongodb.arbiter.service.nameOverride" . }}" + - name: MONGODB_REPLICA_SET_MODE + value: "arbiter" + - name: MONGODB_INITIAL_PRIMARY_HOST + value: {{ printf "%s-0.%s.$(MY_POD_NAMESPACE).svc.%s" (include "mongodb.fullname" .) (include "mongodb.service.nameOverride" .) .Values.clusterDomain }} + - name: MONGODB_REPLICA_SET_NAME + value: {{ .Values.replicaSetName | quote }} + - name: MONGODB_ADVERTISED_HOSTNAME + value: "$(MY_POD_NAME).$(K8S_SERVICE_NAME).$(MY_POD_NAMESPACE).svc.{{ .Values.clusterDomain }}" + - name: MONGODB_PORT_NUMBER + value: {{ .Values.arbiter.containerPorts.mongodb | quote }} + - name: MONGODB_ENABLE_IPV6 + value: {{ ternary "yes" "no" .Values.enableIPv6 | quote }} + {{- if .Values.auth.enabled }} + - name: MONGODB_INITIAL_PRIMARY_ROOT_USER + value: {{ .Values.auth.rootUser | quote }} + - name: MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-root-password + - name: MONGODB_REPLICA_SET_KEY + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-replica-set-key + {{- end }} + - name: ALLOW_EMPTY_PASSWORD + value: {{ ternary "no" "yes" .Values.auth.enabled | quote }} + {{- $extraFlags := .Values.arbiter.extraFlags | join " " -}} + {{- if and .Values.tls.enabled .Values.arbiter.enabled }} + {{- $extraFlags = printf "--tlsMode=%s --tlsCertificateKeyFile=/certs/mongodb.pem --tlsCAFile=/certs/mongodb-ca-cert %s" .Values.tls.mode $extraFlags }} + {{- end }} + {{- if ne $extraFlags "" }} + - name: MONGODB_EXTRA_FLAGS + value: {{ $extraFlags | quote }} + {{- end }} + {{- if and .Values.tls.enabled .Values.arbiter.enabled }} + - name: MONGODB_CLIENT_EXTRA_FLAGS + value: --tls --tlsCertificateKeyFile=/certs/mongodb.pem --tlsCAFile=/certs/mongodb-ca-cert + {{- end }} + {{- if .Values.arbiter.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + {{- if or .Values.arbiter.extraEnvVarsCM .Values.arbiter.extraEnvVarsSecret }} + envFrom: + {{- if .Values.arbiter.extraEnvVarsCM }} + - configMapRef: + name: {{ tpl .Values.arbiter.extraEnvVarsCM . | quote }} + {{- end }} + {{- if .Values.arbiter.extraEnvVarsSecret }} + - secretRef: + name: {{ tpl .Values.arbiter.extraEnvVarsSecret . | quote }} + {{- end }} + {{- end }} + ports: + - containerPort: {{ .Values.arbiter.containerPorts.mongodb }} + name: mongodb + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.arbiter.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.customLivenessProbe "context" $) | nindent 12 }} + {{- else if .Values.arbiter.livenessProbe.enabled }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.arbiter.livenessProbe "enabled") "context" $) | nindent 12 }} + tcpSocket: + port: mongodb + {{- end }} + {{- if .Values.arbiter.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.customReadinessProbe "context" $) | nindent 12 }} + {{- else if .Values.arbiter.readinessProbe.enabled }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.arbiter.readinessProbe "enabled") "context" $) | nindent 12 }} + tcpSocket: + port: mongodb + {{- end }} + {{- if .Values.arbiter.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.arbiter.startupProbe.enabled }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.arbiter.startupProbe "enabled") "context" $) | nindent 12 }} + tcpSocket: + port: mongodb + {{- end }} + {{- end }} + {{- if .Values.arbiter.resources }} + resources: {{- toYaml .Values.arbiter.resources | nindent 12 }} + {{- end }} + {{- if or .Values.arbiter.configuration .Values.arbiter.existingConfigmap .Values.arbiter.extraVolumeMounts .Values.tls.enabled }} + volumeMounts: + {{- if or .Values.arbiter.configuration .Values.arbiter.existingConfigmap }} + - name: config + mountPath: /opt/bitnami/mongodb/conf/mongodb.conf + subPath: mongodb.conf + {{- end }} + {{- if and .Values.tls.enabled .Values.arbiter.enabled }} + - name: certs + mountPath: /certs + {{- end }} + {{- if .Values.arbiter.extraVolumeMounts }} + {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.extraVolumeMounts "context" $) | nindent 12 }} + {{- end }} + {{- end }} + {{- if .Values.arbiter.sidecars }} + {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.sidecars "context" $) | nindent 8 }} + {{- end }} + {{- if or .Values.arbiter.configuration .Values.arbiter.existingConfigmap .Values.arbiter.extraVolumes .Values.tls.enabled }} + volumes: + - name: common-scripts + configMap: + name: {{ printf "%s-common-scripts" (include "mongodb.fullname" .) }} + defaultMode: 0555 + {{- if or .Values.arbiter.configuration .Values.arbiter.existingConfigmap }} + - name: config + configMap: + name: {{ include "mongodb.arbiter.configmapName" . }} + {{- end }} + {{- if and .Values.tls.enabled .Values.arbiter.enabled }} + - name: certs + emptyDir: {} + {{- if (include "mongodb.autoGenerateCerts" .) }} + - name: certs-volume + secret: + secretName: {{ template "mongodb.tlsSecretName" . }} + items: + - key: mongodb-ca-cert + path: mongodb-ca-cert + mode: 0600 + - key: mongodb-ca-key + path: mongodb-ca-key + mode: 0600 + {{- else }} + - name: mongodb-certs-0 + secret: + secretName: {{ include "common.tplvalues.render" ( dict "value" .Values.tls.arbiter.existingSecret "context" $) }} + defaultMode: 256 + {{- end }} + {{- end }} + {{- if .Values.arbiter.extraVolumes }} + {{- include "common.tplvalues.render" (dict "value" .Values.arbiter.extraVolumes "context" $) | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/common-scripts-cm.yaml b/deployment/charts/mongodb/templates/common-scripts-cm.yaml new file mode 100644 index 0000000..ad7856a --- /dev/null +++ b/deployment/charts/mongodb/templates/common-scripts-cm.yaml @@ -0,0 +1,122 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-common-scripts" (include "mongodb.fullname" .) }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: mongodb + {{- 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: + {{- $fullname := include "mongodb.fullname" . }} + startup-probe.sh: | + #!/bin/bash + {{- if .Values.tls.enabled }} + TLS_OPTIONS='--tls --tlsCertificateKeyFile=/certs/mongodb.pem --tlsCAFile=/certs/mongodb-ca-cert' + {{- end }} + mongosh $TLS_OPTIONS --port $MONGODB_PORT_NUMBER --eval 'db.hello().isWritablePrimary || db.hello().secondary' | grep 'true' + readiness-probe.sh: | + #!/bin/bash + {{- if .Values.tls.enabled }} + TLS_OPTIONS='--tls --tlsCertificateKeyFile=/certs/mongodb.pem --tlsCAFile=/certs/mongodb-ca-cert' + {{- end }} + # Run the proper check depending on the version + [[ $(mongod -version | grep "db version") =~ ([0-9]+\.[0-9]+\.[0-9]+) ]] && VERSION=${BASH_REMATCH[1]} + . /opt/bitnami/scripts/libversion.sh + VERSION_MAJOR="$(get_sematic_version "$VERSION" 1)" + VERSION_MINOR="$(get_sematic_version "$VERSION" 2)" + VERSION_PATCH="$(get_sematic_version "$VERSION" 3)" + if [[ ( "$VERSION_MAJOR" -ge 5 ) || ( "$VERSION_MAJOR" -ge 4 && "$VERSION_MINOR" -ge 4 && "$VERSION_PATCH" -ge 2 ) ]]; then + mongosh $TLS_OPTIONS --port $MONGODB_PORT_NUMBER --eval 'db.hello().isWritablePrimary || db.hello().secondary' | grep 'true' + else + mongosh $TLS_OPTIONS --port $MONGODB_PORT_NUMBER --eval 'db.isMaster().ismaster || db.isMaster().secondary' | grep 'true' + fi + ping-mongodb.sh: | + #!/bin/bash + {{- if .Values.tls.enabled }} + TLS_OPTIONS='--tls --tlsCertificateKeyFile=/certs/mongodb.pem --tlsCAFile=/certs/mongodb-ca-cert' + {{- end }} + mongosh $TLS_OPTIONS --port $MONGODB_PORT_NUMBER --eval "db.adminCommand('ping')" + {{- if .Values.tls.enabled }} + generate-certs.sh: | + #!/bin/bash + {{- if (include "mongodb.autoGenerateCerts" .) }} + additional_ips=() + additional_names=() + while getopts "i:n:s:" flag + do + case "${flag}" in + i) read -a additional_ips <<< ${OPTARG//,/ } ;; + n) read -a additional_names <<< ${OPTARG//,/ } ;; + s) svc=${OPTARG// /} ;; + \?) exit 1 ;; + esac + done + + my_hostname=$(hostname) + cp /certs/CAs/* /certs/ + cat >/certs/openssl.cnf <>/certs/openssl.cnf <>/certs/openssl.cnf < /certs/mongodb.pem + cd /certs/ + shopt -s extglob + rm -rf !(mongodb-ca-cert|mongodb.pem|CAs|openssl.cnf) + chmod 0600 mongodb-ca-cert mongodb.pem + {{- else }} + {{- if eq .Values.architecture "standalone" }} + ID="0" + {{- else }} + if [[ "$MY_POD_NAME" =~ "arbiter-0"$ ]]; then + ID="0" + elif [[ "$MY_POD_NAME" =~ "hidden-"[0-9]{1,}$ ]]; then + ID="${MY_POD_NAME#"{{ printf "%s-hidden-" $fullname }}"}" + else + ID="${MY_POD_NAME#"{{ $fullname }}-"}" + fi + {{- end }} + cat "/certs-${ID}/tls.crt" "/certs-${ID}/tls.key" > "/certs/mongodb.pem" + cp "/certs-${ID}/ca.crt" "/certs/mongodb-ca-cert" + chmod 0600 /certs/mongodb-ca-cert /certs/mongodb.pem + {{- end }} + {{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/tcp-configmap.yaml b/deployment/charts/mongodb/templates/configmap.yaml similarity index 52% rename from deployment/deployment/nginx-ingress-controller/templates/tcp-configmap.yaml rename to deployment/charts/mongodb/templates/configmap.yaml index 0f5fda6..76608c4 100644 --- a/deployment/deployment/nginx-ingress-controller/templates/tcp-configmap.yaml +++ b/deployment/charts/mongodb/templates/configmap.yaml @@ -1,16 +1,18 @@ -{{- if .Values.tcp }} +{{- if (include "mongodb.createConfigmap" .) }} apiVersion: v1 kind: ConfigMap metadata: - name: {{ printf "%s-tcp" (include "common.names.fullname" .) }} - namespace: {{ .Release.Namespace | quote }} + name: {{ include "mongodb.fullname" . }} + namespace: {{ include "mongodb.namespace" . | quote }} labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: controller + app.kubernetes.io/component: mongodb {{- if .Values.commonLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- 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: {{- include "common.tplvalues.render" (dict "value" .Values.tcp "context" $) | nindent 2 }} +data: + mongodb.conf: |- + {{- include "common.tplvalues.render" (dict "value" .Values.configuration "context" $) | nindent 4 }} {{- end }} diff --git a/deployment/charts/mongodb/templates/extra-list.yaml b/deployment/charts/mongodb/templates/extra-list.yaml new file mode 100644 index 0000000..9ac65f9 --- /dev/null +++ b/deployment/charts/mongodb/templates/extra-list.yaml @@ -0,0 +1,4 @@ +{{- range .Values.extraDeploy }} +--- +{{ include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/hidden/configmap.yaml b/deployment/charts/mongodb/templates/hidden/configmap.yaml new file mode 100644 index 0000000..d7271f0 --- /dev/null +++ b/deployment/charts/mongodb/templates/hidden/configmap.yaml @@ -0,0 +1,15 @@ +{{- if (include "mongodb.hidden.createConfigmap" .) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-hidden" (include "mongodb.fullname" .) }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: hidden + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} +data: + mongodb.conf: |- + {{- include "common.tplvalues.render" (dict "value" .Values.hidden.configuration "context" $) | nindent 4 }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/hidden/external-access-svc.yaml b/deployment/charts/mongodb/templates/hidden/external-access-svc.yaml new file mode 100644 index 0000000..4437351 --- /dev/null +++ b/deployment/charts/mongodb/templates/hidden/external-access-svc.yaml @@ -0,0 +1,70 @@ +{{- if and (include "mongodb.hidden.enabled" .) .Values.externalAccess.hidden.enabled }} +{{- $fullName := include "mongodb.fullname" . }} +{{- $replicaCount := .Values.hidden.replicaCount | int }} +{{- $root := . }} + +{{- range $i, $e := until $replicaCount }} +{{- $targetPod := printf "%s-hidden-%d" (printf "%s" $fullName) $i }} +{{- $_ := set $ "targetPod" $targetPod }} +apiVersion: v1 +kind: Service +metadata: + name: {{ printf "%s-hidden-%d-external" $fullName $i }} + namespace: {{ include "mongodb.namespace" $ }} + labels: {{- include "common.labels.standard" $ | nindent 4 }} + app.kubernetes.io/component: hidden + {{- if $root.Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" $root.Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + pod: {{ $targetPod }} + {{- if or $root.Values.externalAccess.hidden.service.annotations $root.Values.commonAnnotations }} + annotations: + {{- if $root.Values.externalAccess.hidden.service.annotations }} + {{- include "common.tplvalues.render" ( dict "value" $root.Values.externalAccess.hidden.service.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if $root.Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" $root.Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: {{ $root.Values.externalAccess.hidden.service.type }} + {{- if eq $root.Values.externalAccess.hidden.service.type "LoadBalancer" }} + {{- if not (empty $root.Values.externalAccess.hidden.service.loadBalancerIPs) }} + loadBalancerIP: {{ index $root.Values.externalAccess.hidden.service.loadBalancerIPs $i }} + {{- end }} + {{- if $root.Values.externalAccess.hidden.service.loadBalancerClass }} + loadBalancerClass: {{ $root.Values.externalAccess.hidden.service.loadBalancerClass }} + {{- end }} + {{- if $root.Values.externalAccess.hidden.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: {{- toYaml $root.Values.externalAccess.hidden.service.loadBalancerSourceRanges | nindent 4 }} + {{- end }} + {{- end }} + {{- if (or (eq $root.Values.externalAccess.hidden.service.type "LoadBalancer") (eq $root.Values.externalAccess.hidden.service.type "NodePort")) }} + externalTrafficPolicy: {{ $root.Values.externalAccess.hidden.service.externalTrafficPolicy | quote }} + {{- end }} + {{- if $root.Values.externalAccess.hidden.service.sessionAffinity }} + sessionAffinity: {{ $root.Values.externalAccess.hidden.service.sessionAffinity }} + {{- end }} + {{- if $root.Values.externalAccess.hidden.service.sessionAffinityConfig }} + sessionAffinityConfig: {{- include "common.tplvalues.render" (dict "value" $root.Values.externalAccess.hidden.service.sessionAffinityConfig "context" $) | nindent 4 }} + {{- end }} + publishNotReadyAddresses: true + ports: + - name: {{ $root.Values.externalAccess.hidden.service.portName | quote }} + port: {{ $root.Values.externalAccess.hidden.service.ports.mongodb }} + {{- if not (empty $root.Values.externalAccess.hidden.service.nodePorts) }} + {{- $nodePort := index $root.Values.externalAccess.hidden.service.nodePorts $i }} + nodePort: {{ $nodePort }} + {{- else }} + nodePort: null + {{- end }} + targetPort: mongodb + {{- if $root.Values.externalAccess.hidden.service.extraPorts }} + {{- include "common.tplvalues.render" (dict "value" $root.Values.externalAccess.hidden.service.extraPorts "context" $) | nindent 4 }} + {{- end }} + selector: {{- include "common.labels.matchLabels" $ | nindent 4 }} + app.kubernetes.io/component: hidden + statefulset.kubernetes.io/pod-name: {{ $targetPod }} +--- +{{- end }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/hidden/headless-svc.yaml b/deployment/charts/mongodb/templates/hidden/headless-svc.yaml new file mode 100644 index 0000000..725e025 --- /dev/null +++ b/deployment/charts/mongodb/templates/hidden/headless-svc.yaml @@ -0,0 +1,34 @@ +{{- if (include "mongodb.hidden.enabled" .) }} +apiVersion: v1 +kind: Service +metadata: + name: {{ printf "%s-hidden-headless" (include "mongodb.fullname" .) }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: hidden + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if or .Values.hidden.service.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.hidden.service.annotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.hidden.service.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: ClusterIP + clusterIP: None + publishNotReadyAddresses: true + ports: + - name: {{ .Values.hidden.service.portName | quote }} + port: {{ .Values.hidden.service.ports.mongodb }} + targetPort: mongodb + {{- if .Values.hidden.service.extraPorts }} + {{- include "common.tplvalues.render" (dict "value" .Values.hidden.service.extraPorts "context" $) | nindent 4 }} + {{- end }} + selector: {{- include "common.labels.matchLabels" . | nindent 4 }} + app.kubernetes.io/component: hidden +{{- end }} diff --git a/deployment/charts/mongodb/templates/hidden/pdb.yaml b/deployment/charts/mongodb/templates/hidden/pdb.yaml new file mode 100644 index 0000000..ce233db --- /dev/null +++ b/deployment/charts/mongodb/templates/hidden/pdb.yaml @@ -0,0 +1,22 @@ +{{- if and (include "mongodb.hidden.enabled" .) .Values.hidden.pdb.create }} +apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ printf "%s-hidden" (include "mongodb.fullname" . )}} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: hidden + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- if .Values.hidden.pdb.minAvailable }} + minAvailable: {{ .Values.hidden.pdb.minAvailable }} + {{- end }} + {{- if .Values.hidden.pdb.maxUnavailable }} + maxUnavailable: {{ .Values.hidden.pdb.maxUnavailable }} + {{- end }} + selector: + matchLabels: {{ include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: hidden +{{- end }} diff --git a/deployment/charts/mongodb/templates/hidden/statefulset.yaml b/deployment/charts/mongodb/templates/hidden/statefulset.yaml new file mode 100644 index 0000000..ddc7033 --- /dev/null +++ b/deployment/charts/mongodb/templates/hidden/statefulset.yaml @@ -0,0 +1,556 @@ +{{- if (include "mongodb.hidden.enabled" .) }} +{{- $replicaCount := int .Values.hidden.replicaCount }} +{{- $loadBalancerIPListLength := len .Values.externalAccess.hidden.service.loadBalancerIPs }} +{{- if not (and .Values.externalAccess.hidden.enabled (not .Values.externalAccess.autoDiscovery.enabled) (not (eq $replicaCount $loadBalancerIPListLength )) (eq .Values.externalAccess.hidden.service.type "LoadBalancer")) }} +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ printf "%s-hidden" (include "mongodb.fullname" .) }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: hidden + {{- if .Values.hidden.labels }} + {{- include "common.tplvalues.render" (dict "value" .Values.hidden.labels "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.hidden.annotations }} + annotations: {{- include "common.tplvalues.render" (dict "value" .Values.hidden.annotations "context" $) | nindent 4 }} + {{- end }} +spec: + serviceName: {{ printf "%s-hidden-headless" (include "mongodb.fullname" .) }} + podManagementPolicy: {{ .Values.hidden.podManagementPolicy }} + replicas: {{ .Values.hidden.replicaCount }} + {{- if .Values.hidden.updateStrategy }} + updateStrategy: {{- toYaml .Values.hidden.updateStrategy | nindent 4 }} + {{- end }} + selector: + matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: hidden + template: + metadata: + labels: {{- include "common.labels.standard" . | nindent 8 }} + app.kubernetes.io/component: hidden + {{- if .Values.hidden.podLabels }} + {{- include "common.tplvalues.render" (dict "value" .Values.hidden.podLabels "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 8 }} + {{- end }} + {{- if or (include "mongodb.hidden.createConfigmap" .) .Values.hidden.podAnnotations }} + annotations: + {{- if (include "mongodb.hidden.createConfigmap" .) }} + checksum/configuration: {{ include (print $.Template.BasePath "/hidden/configmap.yaml") . | sha256sum }} + {{- end }} + {{- if .Values.hidden.podAnnotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.hidden.podAnnotations "context" $) | nindent 8 }} + {{- end }} + {{- end }} + spec: + {{- include "mongodb.imagePullSecrets" . | nindent 6 }} + {{- if .Values.hidden.schedulerName }} + schedulerName: {{ .Values.hidden.schedulerName | quote }} + {{- end }} + serviceAccountName: {{ template "mongodb.serviceAccountName" . }} + {{- if .Values.hidden.hostAliases }} + hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.hidden.hostAliases "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.hidden.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.hidden.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.hidden.podAffinityPreset "component" "" "topologyKey" .Values.topologyKey "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.hidden.podAntiAffinityPreset "component" "" "topologyKey" .Values.topologyKey "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.hidden.nodeAffinityPreset.type "key" .Values.hidden.nodeAffinityPreset.key "values" .Values.hidden.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.hidden.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.hidden.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.hidden.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.hidden.tolerations "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.hidden.topologySpreadConstraints }} + topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.hidden.topologySpreadConstraints "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.hidden.priorityClassName }} + priorityClassName: {{ .Values.hidden.priorityClassName }} + {{- end }} + {{- if .Values.hidden.runtimeClassName }} + runtimeClassName: {{ .Values.hidden.runtimeClassName }} + {{- end }} + {{- if .Values.hidden.podSecurityContext.enabled }} + securityContext: {{- omit .Values.hidden.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{ if .Values.hidden.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.hidden.terminationGracePeriodSeconds }} + {{- end }} + {{- if or .Values.hidden.initContainers (and .Values.volumePermissions.enabled .Values.hidden.persistence.enabled) (and .Values.externalAccess.hidden.enabled .Values.externalAccess.autoDiscovery.enabled) .Values.tls.enabled }} + initContainers: + {{- if .Values.hidden.initContainers }} + {{- include "common.tplvalues.render" (dict "value" .Values.hidden.initContainers "context" $) | nindent 8 }} + {{- end }} + {{- if and .Values.volumePermissions.enabled .Values.hidden.persistence.enabled }} + - name: volume-permissions + image: {{ include "mongodb.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + command: + - /bin/bash + args: + - -ec + - | + mkdir -p {{ printf "%s/%s" .Values.hidden.persistence.mountPath (default "" .Values.hidden.persistence.subPath) }} + chown {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} {{ printf "%s/%s" .Values.hidden.persistence.mountPath (default "" .Values.hidden.persistence.subPath) }} + find {{ printf "%s/%s" .Values.hidden.persistence.mountPath (default "" .Values.hidden.persistence.subPath) }} -mindepth 1 -maxdepth 1 -not -name ".snapshot" -not -name "lost+found" | xargs -r chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + securityContext: {{- omit .Values.volumePermissions.securityContext "runAsUser" | toYaml | nindent 12 }} + {{- else }} + securityContext: {{- .Values.volumePermissions.securityContext | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.volumePermissions.resources }} + resources: {{- toYaml .Values.volumePermissions.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: datadir + mountPath: {{ .Values.hidden.persistence.mountPath }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: generate-tls-certs + image: {{ include "mongodb.tls.image" . }} + imagePullPolicy: {{ .Values.tls.image.pullPolicy | quote }} + env: + - name: MY_POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: MY_POD_HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + volumeMounts: + {{- if (include "mongodb.autoGenerateCerts" .) }} + - name: certs-volume + mountPath: /certs/CAs + {{- else }} + {{- range $index, $_ := .Values.tls.hidden.existingSecrets }} + - name: mongodb-certs-{{ $index }} + mountPath: /certs-{{ $index }} + {{- end }} + {{- end }} + - name: certs + mountPath: /certs + - name: common-scripts + mountPath: /bitnami/scripts + command: + - /bitnami/scripts/generate-certs.sh + args: + - -s {{ printf "%s-hidden-headless" (include "mongodb.fullname" .) }} + {{- if .Values.externalAccess.hidden.service.loadBalancerIPs }} + - -i {{ join "," .Values.externalAccess.hidden.service.loadBalancerIPs }} + {{- end }} + {{- if .Values.tls.extraDnsNames }} + - -n {{ join "," .Values.tls.extraDnsNames }} + {{- end }} + {{- if .Values.tls.resources }} + resources: {{- toYaml .Values.tls.resources | nindent 12 }} + {{- end }} + {{- end }} + {{- if and .Values.externalAccess.hidden.enabled .Values.externalAccess.autoDiscovery.enabled (eq .Values.externalAccess.hidden.service.type "LoadBalancer") }} + - name: auto-discovery + image: {{ include "mongodb.externalAccess.autoDiscovery.image" . }} + imagePullPolicy: {{ .Values.externalAccess.autoDiscovery.image.pullPolicy | quote }} + command: + - /scripts/auto-discovery.sh + env: + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: SHARED_FILE + value: "/shared/info.txt" + {{- if .Values.externalAccess.autoDiscovery.resources }} + resources: {{- toYaml .Values.externalAccess.autoDiscovery.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: shared + mountPath: /shared + - name: scripts + mountPath: /scripts/auto-discovery.sh + subPath: auto-discovery.sh + {{- end }} + {{- end }} + containers: + - name: mongodb + image: {{ include "mongodb.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy | quote }} + {{- if .Values.hidden.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.hidden.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.hidden.command }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.hidden.command "context" $) | nindent 12 }} + {{- else }} + command: + - /scripts/setup-hidden.sh + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} + {{- else if .Values.hidden.args }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.hidden.args "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.hidden.lifecycleHooks }} + lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.hidden.lifecycleHooks "context" $) | nindent 12 }} + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" (or .Values.image.debug .Values.diagnosticMode.enabled) | quote }} + {{- if and .Values.externalAccess.hidden.enabled .Values.externalAccess.autoDiscovery.enabled (eq .Values.externalAccess.hidden.service.type "LoadBalancer") }} + - name: SHARED_FILE + value: "/shared/info.txt" + {{- end }} + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: MY_POD_HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: MY_POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: K8S_SERVICE_NAME + value: "{{ include "mongodb.service.nameOverride" . }}" + - name: K8S_HIDDEN_NODE_SERVICE_NAME + value: "{{ include "mongodb.fullname" . }}-hidden-headless" + - name: MONGODB_REPLICA_SET_MODE + value: "hidden" + - name: MONGODB_INITIAL_PRIMARY_HOST + value: {{ printf "%s-0.$(K8S_SERVICE_NAME).$(MY_POD_NAMESPACE).svc.%s" (include "mongodb.fullname" .) .Values.clusterDomain }} + - name: MONGODB_REPLICA_SET_NAME + value: {{ .Values.replicaSetName | quote }} + {{- if and .Values.replicaSetHostnames (not .Values.externalAccess.hidden.enabled) }} + - name: MONGODB_ADVERTISED_HOSTNAME + value: "$(MY_POD_NAME).$(K8S_HIDDEN_NODE_SERVICE_NAME).$(MY_POD_NAMESPACE).svc.{{ .Values.clusterDomain }}" + {{- end }} + {{- $customUsers := include "mongodb.customUsers" . -}} + {{- $customDatabases := include "mongodb.customDatabases" . -}} + {{- if not (empty $customUsers) }} + - name: MONGODB_EXTRA_USERNAMES + value: {{ $customUsers | quote }} + {{- end }} + {{- if not (empty $customDatabases) }} + - name: MONGODB_EXTRA_DATABASES + value: {{ $customDatabases | quote }} + {{- end }} + {{- if .Values.auth.enabled }} + {{- if and (not (empty $customUsers)) (not (empty $customDatabases)) }} + - name: MONGODB_EXTRA_PASSWORDS + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-passwords + {{- end }} + - name: MONGODB_ROOT_USER + value: {{ .Values.auth.rootUser | quote }} + - name: MONGODB_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-root-password + - name: MONGODB_REPLICA_SET_KEY + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-replica-set-key + {{- end }} + {{- if and .Values.metrics.enabled (not (empty .Values.metrics.username)) }} + - name: MONGODB_METRICS_USERNAME + value: {{ .Values.metrics.username | quote }} + {{- if .Values.auth.enabled }} + - name: MONGODB_METRICS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-metrics-password + {{- end }} + {{- end }} + - name: ALLOW_EMPTY_PASSWORD + value: {{ ternary "no" "yes" .Values.auth.enabled | quote }} + - name: MONGODB_SYSTEM_LOG_VERBOSITY + value: {{ .Values.systemLogVerbosity | quote }} + - name: MONGODB_DISABLE_SYSTEM_LOG + value: {{ ternary "yes" "no" .Values.disableSystemLog | quote }} + - name: MONGODB_DISABLE_JAVASCRIPT + value: {{ ternary "yes" "no" .Values.disableJavascript | quote }} + - name: MONGODB_ENABLE_JOURNAL + value: {{ ternary "yes" "no" .Values.enableJournal | quote }} + - name: MONGODB_PORT_NUMBER + value: {{ .Values.hidden.containerPorts.mongodb | quote }} + - name: MONGODB_ENABLE_IPV6 + value: {{ ternary "yes" "no" .Values.enableIPv6 | quote }} + - name: MONGODB_ENABLE_DIRECTORY_PER_DB + value: {{ ternary "yes" "no" .Values.directoryPerDB | quote }} + {{- $extraFlags := .Values.hidden.extraFlags | join " " -}} + {{- if .Values.tls.enabled }} + {{- $extraFlags = printf "--tlsMode=%s --tlsCertificateKeyFile=/certs/mongodb.pem --tlsCAFile=/certs/mongodb-ca-cert %s" .Values.tls.mode $extraFlags }} + {{- end }} + {{- if ne $extraFlags "" }} + - name: MONGODB_EXTRA_FLAGS + value: {{ $extraFlags | quote }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: MONGODB_CLIENT_EXTRA_FLAGS + value: --tls --tlsCertificateKeyFile=/certs/mongodb.pem --tlsCAFile=/certs/mongodb-ca-cert + {{- end }} + {{- if .Values.hidden.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.hidden.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + {{- if or .Values.hidden.extraEnvVarsCM .Values.hidden.extraEnvVarsSecret }} + envFrom: + {{- if .Values.hidden.extraEnvVarsCM }} + - configMapRef: + name: {{ tpl .Values.hidden.extraEnvVarsCM . | quote }} + {{- end }} + {{- if .Values.hidden.extraEnvVarsSecret }} + - secretRef: + name: {{ tpl .Values.hidden.extraEnvVarsSecret . | quote }} + {{- end }} + {{- end }} + ports: + - containerPort: {{ .Values.hidden.containerPorts.mongodb }} + name: mongodb + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.hidden.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.hidden.customLivenessProbe "context" $) | nindent 12 }} + {{- else if .Values.hidden.livenessProbe.enabled }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.hidden.livenessProbe "enabled") "context" $) | nindent 12 }} + exec: + command: + - /bitnami/scripts/ping-mongodb.sh + {{- end }} + {{- if .Values.hidden.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.hidden.customReadinessProbe "context" $) | nindent 12 }} + {{- else if .Values.hidden.readinessProbe.enabled }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.hidden.readinessProbe "enabled") "context" $) | nindent 12 }} + exec: + command: + - /bitnami/scripts/ping-mongodb.sh + {{- end }} + {{- if .Values.hidden.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.hidden.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.hidden.startupProbe.enabled }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.hidden.startupProbe "enabled") "context" $) | nindent 12 }} + exec: + command: + - /bitnami/scripts/startup-probe.sh + {{- end }} + {{- end }} + {{- if .Values.hidden.resources }} + resources: {{- toYaml .Values.hidden.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: datadir + mountPath: {{ .Values.hidden.persistence.mountPath }} + subPath: {{ .Values.hidden.persistence.subPath }} + - name: common-scripts + mountPath: /bitnami/scripts + {{- if or .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + mountPath: /docker-entrypoint-initdb.d + {{- end }} + {{- if or .Values.hidden.configuration .Values.hidden.existingConfigmap }} + - name: config + mountPath: /opt/bitnami/mongodb/conf/mongodb.conf + subPath: mongodb.conf + {{- end }} + - name: scripts + mountPath: /scripts/setup-hidden.sh + subPath: setup-hidden.sh + {{- if and .Values.externalAccess.hidden.enabled .Values.externalAccess.autoDiscovery.enabled (eq .Values.externalAccess.hidden.service.type "LoadBalancer") }} + - name: shared + mountPath: /shared + {{- end }} + {{- if .Values.tls.enabled }} + - name: certs + mountPath: /certs + {{- end }} + {{- if .Values.hidden.extraVolumeMounts }} + {{- include "common.tplvalues.render" (dict "value" .Values.hidden.extraVolumeMounts "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.metrics.enabled }} + - name: metrics + image: {{ template "mongodb.metrics.image" . }} + imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.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.metrics.command }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.command "context" $) | nindent 12 }} + {{- else }} + command: + - /bin/bash + - -ec + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} + {{- else if .Values.metrics.args }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.args "context" $) | nindent 12 }} + {{- else }} + args: + - | + /bin/mongodb_exporter --mongodb.uri "{{ include "mongodb.mongodb_exporter.uri" . }}" {{ .Values.metrics.extraFlags }} + {{- end }} + env: + {{- if .Values.auth.enabled }} + {{- if not .Values.metrics.username }} + - name: MONGODB_ROOT_USER + value: {{ .Values.auth.rootUser | quote }} + - name: MONGODB_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-root-password + {{- else }} + - name: MONGODB_METRICS_USERNAME + value: {{ .Values.metrics.username | quote }} + - name: MONGODB_METRICS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-metrics-password + {{- end }} + {{- end }} + volumeMounts: + {{- if .Values.tls.enabled }} + - name: certs + mountPath: /certs + {{- end }} + ports: + - name: metrics + containerPort: 9216 + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.metrics.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customLivenessProbe "context" $) | nindent 12 }} + {{- else if .Values.metrics.livenessProbe.enabled }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.livenessProbe "enabled") "context" $) | nindent 12 }} + httpGet: + path: /metrics + port: metrics + {{- end }} + {{- if .Values.metrics.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customReadinessProbe "context" $) | nindent 12 }} + {{- else if .Values.metrics.readinessProbe.enabled }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.readinessProbe "enabled") "context" $) | nindent 12 }} + httpGet: + path: /metrics + port: metrics + {{- end }} + {{- if .Values.metrics.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.metrics.startupProbe.enabled }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.startupProbe "enabled") "context" $) | nindent 12 }} + tcpSocket: + port: metrics + {{- end }} + {{- end }} + {{- if .Values.metrics.resources }} + resources: {{- toYaml .Values.metrics.resources | nindent 12 }} + {{- end }} + {{- end }} + {{- if .Values.hidden.sidecars }} + {{- include "common.tplvalues.render" (dict "value" .Values.hidden.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + - name: common-scripts + configMap: + name: {{ printf "%s-common-scripts" (include "mongodb.fullname" .) }} + defaultMode: 0555 + {{- if or .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + configMap: + name: {{ template "mongodb.initdbScriptsCM" . }} + {{- end }} + {{- if or .Values.hidden.configuration .Values.hidden.existingConfigmap }} + - name: config + configMap: + name: {{ include "mongodb.hidden.configmapName" . }} + {{- end }} + {{- if and .Values.externalAccess.hidden.enabled .Values.externalAccess.autoDiscovery.enabled (eq .Values.externalAccess.hidden.service.type "LoadBalancer") }} + - name: shared + emptyDir: {} + {{- end }} + - name: scripts + configMap: + name: {{ printf "%s-scripts" (include "mongodb.fullname" .) }} + defaultMode: 0755 + {{- if .Values.hidden.extraVolumes }} + {{- include "common.tplvalues.render" (dict "value" .Values.hidden.extraVolumes "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: certs + emptyDir: {} + {{- if (include "mongodb.autoGenerateCerts" .) }} + - name: certs-volume + secret: + secretName: {{ template "mongodb.tlsSecretName" . }} + items: + - key: mongodb-ca-cert + path: mongodb-ca-cert + mode: 0600 + - key: mongodb-ca-key + path: mongodb-ca-key + mode: 0600 + {{- else }} + {{- range $index, $secret := .Values.tls.hidden.existingSecrets }} + - name: mongodb-certs-{{ $index }} + secret: + secretName: {{ include "common.tplvalues.render" ( dict "value" $secret "context" $) }} + defaultMode: 256 + {{- end }} + {{- end }} + {{- end }} + {{- if not .Values.hidden.persistence.enabled }} + - name: datadir + {{- if .Values.hidden.persistence.medium }} + emptyDir: + medium: {{ .Values.hidden.persistence.medium | quote }} + {{- else }} + emptyDir: {} + {{- end }} + {{- else }} + volumeClaimTemplates: + - metadata: + name: datadir + {{- if .Values.hidden.persistence.annotations }} + annotations: {{- include "common.tplvalues.render" (dict "value" .Values.hidden.persistence.annotations "context" $) | nindent 10 }} + {{- end }} + spec: + accessModes: + {{- range .Values.hidden.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.hidden.persistence.size | quote }} + {{- if .Values.hidden.persistence.volumeClaimTemplates.requests }} + {{- include "common.tplvalues.render" (dict "value" .Values.hidden.persistence.volumeClaimTemplates.requests "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.hidden.persistence.volumeClaimTemplates.dataSource }} + dataSource: {{- include "common.tplvalues.render" (dict "value" .Values.hidden.persistence.volumeClaimTemplates.dataSource "context" $) | nindent 10 }} + {{- end }} + {{- if .Values.hidden.persistence.volumeClaimTemplates.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.hidden.persistence.volumeClaimTemplates.selector "context" $) | nindent 10 }} + {{- end }} + {{ include "common.storage.class" (dict "persistence" .Values.hidden.persistence "global" .Values.global) }} + {{- end }} +{{- end }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/initialization-configmap.yaml b/deployment/charts/mongodb/templates/initialization-configmap.yaml new file mode 100644 index 0000000..f3d023a --- /dev/null +++ b/deployment/charts/mongodb/templates/initialization-configmap.yaml @@ -0,0 +1,17 @@ +{{- if and .Values.initdbScripts (not .Values.initdbScriptsConfigMap) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-init-scripts" (include "mongodb.fullname" .) }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: mongodb + {{- 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: +{{- include "common.tplvalues.render" (dict "value" .Values.initdbScripts "context" .) | nindent 2 }} +{{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/controller-metrics-service.yaml b/deployment/charts/mongodb/templates/metrics-svc.yaml similarity index 53% rename from deployment/deployment/nginx-ingress-controller/templates/controller-metrics-service.yaml rename to deployment/charts/mongodb/templates/metrics-svc.yaml index 305c582..2a36dfc 100644 --- a/deployment/deployment/nginx-ingress-controller/templates/controller-metrics-service.yaml +++ b/deployment/charts/mongodb/templates/metrics-svc.yaml @@ -2,31 +2,32 @@ apiVersion: v1 kind: Service metadata: - name: {{ printf "%s-metrics" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }} - namespace: {{ .Release.Namespace | quote }} + name: {{ printf "%s-metrics" (include "mongodb.fullname" .) }} + namespace: {{ include "mongodb.namespace" . | quote }} labels: {{- include "common.labels.standard" . | nindent 4 }} app.kubernetes.io/component: metrics - {{- if .Values.metrics.service.labels }} - {{- include "common.tplvalues.render" (dict "value" .Values.metrics.service.labels "context" $) | nindent 4 }} - {{- end }} {{- if .Values.commonLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} {{- end }} {{- if or .Values.metrics.service.annotations .Values.commonAnnotations }} annotations: - {{- if .Values.commonAnnotations }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} - {{- end }} {{- if .Values.metrics.service.annotations }} {{- include "common.tplvalues.render" (dict "value" .Values.metrics.service.annotations "context" $) | nindent 4 }} {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} {{- end }} spec: type: {{ .Values.metrics.service.type }} ports: - - name: metrics - port: {{ .Values.metrics.service.port }} + - port: {{ .Values.metrics.service.ports.metrics }} targetPort: metrics - selector: {{- include "common.labels.matchLabels" . | nindent 4 }} - app.kubernetes.io/component: controller + protocol: TCP + name: http-metrics + {{- if .Values.metrics.service.extraPorts }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.service.extraPorts "context" $) | nindent 4 }} + {{- end }} + selector: {{- include "common.labels.matchLabels" $ | nindent 4 }} + app.kubernetes.io/component: mongodb {{- end }} diff --git a/deployment/charts/mongodb/templates/prometheusrule.yaml b/deployment/charts/mongodb/templates/prometheusrule.yaml new file mode 100644 index 0000000..29d2ea4 --- /dev/null +++ b/deployment/charts/mongodb/templates/prometheusrule.yaml @@ -0,0 +1,18 @@ +{{- if and .Values.metrics.enabled .Values.metrics.prometheusRule.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ include "mongodb.fullname" . }} + namespace: {{ include "mongodb.prometheusRule.namespace" . }} + 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.prometheusRule.additionalLabels }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.prometheusRule.additionalLabels "context" $) | nindent 4 }} + {{- end }} +spec: + groups: + - name: {{ include "mongodb.fullname" . }} + rules: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.prometheusRule.rules "context" $ ) | nindent 8 }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/psp.yaml b/deployment/charts/mongodb/templates/psp.yaml new file mode 100644 index 0000000..e9ef023 --- /dev/null +++ b/deployment/charts/mongodb/templates/psp.yaml @@ -0,0 +1,50 @@ +{{- $pspAvailable := (semverCompare "<1.25-0" (include "common.capabilities.kubeVersion" .)) -}} +{{- if and $pspAvailable .Values.podSecurityPolicy.create }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ include "mongodb.fullname" . }} + namespace: {{ include "mongodb.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: +{{- if .Values.podSecurityPolicy.spec }} +{{ include "common.tplvalues.render" ( dict "value" .Values.podSecurityPolicy.spec "context" $ ) | nindent 2 }} +{{- else }} + allowPrivilegeEscalation: {{ .Values.podSecurityPolicy.allowPrivilegeEscalation }} + fsGroup: + rule: 'MustRunAs' + ranges: + - min: {{ .Values.podSecurityContext.fsGroup }} + max: {{ .Values.podSecurityContext.fsGroup }} + hostIPC: false + hostNetwork: false + hostPID: false + privileged: {{ .Values.podSecurityPolicy.privileged }} + readOnlyRootFilesystem: false + requiredDropCapabilities: + - ALL + runAsUser: + rule: 'MustRunAs' + ranges: + - min: {{ .Values.containerSecurityContext.runAsUser }} + max: {{ .Values.containerSecurityContext.runAsUser }} + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: {{ .Values.containerSecurityContext.runAsUser }} + max: {{ .Values.containerSecurityContext.runAsUser }} + volumes: + - 'configMap' + - 'secret' + - 'emptyDir' + - 'persistentVolumeClaim' +{{- end }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/replicaset/external-access-svc.yaml b/deployment/charts/mongodb/templates/replicaset/external-access-svc.yaml new file mode 100644 index 0000000..d09e128 --- /dev/null +++ b/deployment/charts/mongodb/templates/replicaset/external-access-svc.yaml @@ -0,0 +1,70 @@ +{{- if and (eq .Values.architecture "replicaset") .Values.externalAccess.enabled (not (eq .Values.externalAccess.service.type "ClusterIP")) }} +{{- $fullName := include "mongodb.fullname" . }} +{{- $replicaCount := .Values.replicaCount | int }} +{{- $root := . }} + +{{- range $i, $e := until $replicaCount }} +{{- $targetPod := printf "%s-%d" (printf "%s" $fullName) $i }} +{{- $_ := set $ "targetPod" $targetPod }} +apiVersion: v1 +kind: Service +metadata: + name: {{ printf "%s-%d-external" $fullName $i }} + namespace: {{ include "mongodb.namespace" $ }} + labels: {{- include "common.labels.standard" $ | nindent 4 }} + app.kubernetes.io/component: mongodb + {{- if $root.Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" $root.Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + pod: {{ $targetPod }} + {{- if or $root.Values.externalAccess.service.annotations $root.Values.commonAnnotations }} + annotations: + {{- if $root.Values.externalAccess.service.annotations }} + {{- include "common.tplvalues.render" ( dict "value" $root.Values.externalAccess.service.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if $root.Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" $root.Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: {{ $root.Values.externalAccess.service.type }} + {{- if eq $root.Values.externalAccess.service.type "LoadBalancer" }} + {{- if not (empty $root.Values.externalAccess.service.loadBalancerIPs) }} + loadBalancerIP: {{ index $root.Values.externalAccess.service.loadBalancerIPs $i }} + {{- end }} + {{- if and (eq $root.Values.externalAccess.service.type "LoadBalancer") $root.Values.externalAccess.service.loadBalancerClass }} + loadBalancerClass: {{ $root.Values.externalAccess.service.loadBalancerClass }} + {{- end }} + {{- if $root.Values.externalAccess.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: {{- toYaml $root.Values.externalAccess.service.loadBalancerSourceRanges | nindent 4 }} + {{- end }} + {{- end }} + {{- if (or (eq $root.Values.externalAccess.service.type "LoadBalancer") (eq $root.Values.externalAccess.service.type "NodePort")) }} + externalTrafficPolicy: {{ $root.Values.externalAccess.service.externalTrafficPolicy | quote }} + {{- end }} + {{- if $root.Values.externalAccess.service.sessionAffinity }} + sessionAffinity: {{ $root.Values.externalAccess.service.sessionAffinity }} + {{- end }} + {{- if $root.Values.externalAccess.service.sessionAffinityConfig }} + sessionAffinityConfig: {{- include "common.tplvalues.render" (dict "value" $root.Values.externalAccess.service.sessionAffinityConfig "context" $) | nindent 4 }} + {{- end }} + publishNotReadyAddresses: true + ports: + - name: {{ $root.Values.externalAccess.service.portName | quote }} + port: {{ $root.Values.externalAccess.service.ports.mongodb }} + {{- if not (empty $root.Values.externalAccess.service.nodePorts) }} + {{- $nodePort := index $root.Values.externalAccess.service.nodePorts $i }} + nodePort: {{ $nodePort }} + {{- else }} + nodePort: null + {{- end }} + targetPort: mongodb + {{- if $root.Values.externalAccess.service.extraPorts }} + {{- include "common.tplvalues.render" (dict "value" $root.Values.externalAccess.service.extraPorts "context" $) | nindent 4 }} + {{- end }} + selector: {{- include "common.labels.matchLabels" $ | nindent 4 }} + app.kubernetes.io/component: mongodb + statefulset.kubernetes.io/pod-name: {{ $targetPod }} +--- +{{- end }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/replicaset/headless-svc.yaml b/deployment/charts/mongodb/templates/replicaset/headless-svc.yaml new file mode 100644 index 0000000..78f26ab --- /dev/null +++ b/deployment/charts/mongodb/templates/replicaset/headless-svc.yaml @@ -0,0 +1,34 @@ +{{- if eq .Values.architecture "replicaset" }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "mongodb.service.nameOverride" . }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: mongodb + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if or .Values.service.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.service.annotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.service.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: ClusterIP + clusterIP: None + publishNotReadyAddresses: true + ports: + - name: {{ .Values.service.portName | quote }} + port: {{ .Values.service.ports.mongodb }} + targetPort: mongodb + {{- if .Values.service.extraPorts }} + {{- include "common.tplvalues.render" (dict "value" .Values.service.extraPorts "context" $) | nindent 4 }} + {{- end }} + selector: {{- include "common.labels.matchLabels" . | nindent 4 }} + app.kubernetes.io/component: mongodb +{{- end }} diff --git a/deployment/charts/mongodb/templates/replicaset/pdb.yaml b/deployment/charts/mongodb/templates/replicaset/pdb.yaml new file mode 100644 index 0000000..a2b6492 --- /dev/null +++ b/deployment/charts/mongodb/templates/replicaset/pdb.yaml @@ -0,0 +1,25 @@ +{{- if and (eq .Values.architecture "replicaset") .Values.pdb.create }} +apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ include "mongodb.fullname" . }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: mongodb + {{- 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.pdb.minAvailable }} + minAvailable: {{ .Values.pdb.minAvailable }} + {{- end }} + {{- if .Values.pdb.maxUnavailable }} + maxUnavailable: {{ .Values.pdb.maxUnavailable }} + {{- end }} + selector: + matchLabels: {{ include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: mongodb +{{- end }} diff --git a/deployment/charts/mongodb/templates/replicaset/scripts-configmap.yaml b/deployment/charts/mongodb/templates/replicaset/scripts-configmap.yaml new file mode 100644 index 0000000..1046188 --- /dev/null +++ b/deployment/charts/mongodb/templates/replicaset/scripts-configmap.yaml @@ -0,0 +1,305 @@ +{{- if eq .Values.architecture "replicaset" }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-scripts" (include "mongodb.fullname" .) }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: mongodb + {{- 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: + {{- $fullname := include "mongodb.fullname" . }} + {{- $releaseNamespace := include "mongodb.namespace" . }} + {{- if and .Values.externalAccess.autoDiscovery.enabled (eq .Values.externalAccess.service.type "LoadBalancer") }} + auto-discovery.sh: |- + #!/bin/bash + + SVC_NAME="${MY_POD_NAME}-external" + + # Auxiliary functions + retry_while() { + local -r cmd="${1:?cmd is missing}" + local -r retries="${2:-12}" + local -r sleep_time="${3:-5}" + local return_value=1 + + read -r -a command <<< "$cmd" + for ((i = 1 ; i <= retries ; i+=1 )); do + "${command[@]}" && return_value=0 && break + sleep "$sleep_time" + done + return $return_value + } + k8s_svc_lb_ip() { + local namespace=${1:?namespace is missing} + local service=${2:?service is missing} + local service_ip=$(kubectl get svc "$service" -n "$namespace" -o jsonpath="{.status.loadBalancer.ingress[0].ip}") + local service_hostname=$(kubectl get svc "$service" -n "$namespace" -o jsonpath="{.status.loadBalancer.ingress[0].hostname}") + + if [[ -n ${service_ip} ]]; then + echo "${service_ip}" + else + echo "${service_hostname}" + fi + } + k8s_svc_lb_ip_ready() { + local namespace=${1:?namespace is missing} + local service=${2:?service is missing} + [[ -n "$(k8s_svc_lb_ip "$namespace" "$service")" ]] + } + # Wait until LoadBalancer IP is ready + retry_while "k8s_svc_lb_ip_ready {{ $releaseNamespace }} $SVC_NAME" || exit 1 + # Obtain LoadBalancer external IP + k8s_svc_lb_ip "{{ $releaseNamespace }}" "$SVC_NAME" | tee "$SHARED_FILE" + {{- end }} + setup.sh: |- + #!/bin/bash + + . /opt/bitnami/scripts/mongodb-env.sh + . /opt/bitnami/scripts/libfs.sh + . /opt/bitnami/scripts/liblog.sh + . /opt/bitnami/scripts/libvalidations.sh + + {{- if .Values.externalAccess.enabled }} + {{- if eq .Values.externalAccess.service.type "LoadBalancer" }} + {{- if .Values.externalAccess.autoDiscovery.enabled }} + export MONGODB_ADVERTISED_HOSTNAME="$(<${SHARED_FILE})" + {{- else }} + ID="${MY_POD_NAME#"{{ $fullname }}-"}" + export MONGODB_ADVERTISED_HOSTNAME=$(echo '{{ .Values.externalAccess.service.loadBalancerIPs }}' | tr -d '[]' | cut -d ' ' -f "$(($ID + 1))") + {{- end }} + {{- else if eq .Values.externalAccess.service.type "NodePort" }} + ID="${MY_POD_NAME#"{{ $fullname }}-"}" + if is_empty_value "$MONGODB_ADVERTISED_PORT_NUMBER"; then + export MONGODB_ADVERTISED_PORT_NUMBER=$(echo '{{ .Values.externalAccess.service.nodePorts }}' | tr -d '[]' | cut -d ' ' -f "$(($ID + 1))") + fi + {{- if .Values.externalAccess.service.domain }} + export MONGODB_ADVERTISED_HOSTNAME={{ .Values.externalAccess.service.domain }} + {{- else }} + export MONGODB_ADVERTISED_HOSTNAME=$MY_POD_HOST_IP + {{- end }} + {{- end }} + {{- end }} + + {{- if .Values.replicaSetConfigurationSettings.enabled }} + # placed here before root password env is overwritten + # makes no assumption about starting state + # ensures that any stepDown or non-default starting state is handled + /scripts/replicaSetConfigurationSettings.sh & + {{- end }} + + if is_empty_value "$MONGODB_ADVERTISED_PORT_NUMBER"; then + export MONGODB_ADVERTISED_PORT_NUMBER="$MONGODB_PORT_NUMBER" + fi + + info "Advertised Hostname: $MONGODB_ADVERTISED_HOSTNAME" + info "Advertised Port: $MONGODB_ADVERTISED_PORT_NUMBER" + + # Check for existing replica set in case there is no data in the PVC + # This is for cases where the PVC is lost or for MongoDB caches without + # persistence + current_primary="" + if is_dir_empty "${MONGODB_DATA_DIR}/db"; then + info "Data dir empty, checking if the replica set already exists" + {{- $replicaCount := int .Values.replicaCount }} + {{- $portNumber := int .Values.service.ports.mongodb }} + {{- $fullname := include "mongodb.fullname" . }} + {{- $releaseNamespace := include "mongodb.namespace" . }} + {{- $clusterDomain := .Values.clusterDomain }} + {{- $loadBalancerIPListLength := len .Values.externalAccess.service.loadBalancerIPs }} + {{- $mongoList := list }} + {{- range $e, $i := until $replicaCount }} + {{- $mongoList = append $mongoList (printf "%s-%d.%s-headless.%s.svc.%s:%d" $fullname $i $fullname $releaseNamespace $clusterDomain $portNumber) }} + {{- end }} + current_primary=$(mongosh admin --host "{{ join "," $mongoList }}" {{- if .Values.auth.enabled }} --authenticationDatabase admin -u root -p $MONGODB_ROOT_PASSWORD{{- end }}{{- if .Values.tls.enabled}} --tls --tlsCertificateKeyFile=/certs/mongodb.pem --tlsCAFile=/certs/mongodb-ca-cert{{- end }} --eval 'db.runCommand("ismaster")' | awk -F\' '/primary/ {print $2}') + + if ! is_empty_value "$current_primary"; then + info "Detected existing primary: ${current_primary}" + fi + fi + + if ! is_empty_value "$current_primary" && [[ "$MONGODB_ADVERTISED_HOSTNAME:$MONGODB_ADVERTISED_PORT_NUMBER" == "$current_primary" ]]; then + info "Advertised name matches current primary, configuring node as a primary" + export MONGODB_REPLICA_SET_MODE="primary" + elif ! is_empty_value "$current_primary" && [[ "$MONGODB_ADVERTISED_HOSTNAME:$MONGODB_ADVERTISED_PORT_NUMBER" != "$current_primary" ]]; then + info "Current primary is different from this node. Configuring the node as replica of ${current_primary}" + export MONGODB_REPLICA_SET_MODE="secondary" + export MONGODB_INITIAL_PRIMARY_HOST="${current_primary%:*}" + export MONGODB_INITIAL_PRIMARY_PORT_NUMBER="${current_primary#*:}" + export MONGODB_SET_SECONDARY_OK="yes" + elif [[ "$MY_POD_NAME" = "{{ $fullname }}-0" ]]; then + info "Pod name matches initial primary pod name, configuring node as a primary" + export MONGODB_REPLICA_SET_MODE="primary" + else + info "Pod name doesn't match initial primary pod name, configuring node as a secondary" + export MONGODB_REPLICA_SET_MODE="secondary" + export MONGODB_INITIAL_PRIMARY_PORT_NUMBER="$MONGODB_PORT_NUMBER" + fi + + if [[ "$MONGODB_REPLICA_SET_MODE" == "secondary" ]]; then + export MONGODB_INITIAL_PRIMARY_ROOT_USER="$MONGODB_ROOT_USER" + export MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD="$MONGODB_ROOT_PASSWORD" + export MONGODB_ROOT_PASSWORD="" + export MONGODB_EXTRA_USERNAMES="" + export MONGODB_EXTRA_DATABASES="" + export MONGODB_EXTRA_PASSWORDS="" + export MONGODB_ROOT_PASSWORD_FILE="" + export MONGODB_EXTRA_USERNAMES_FILE="" + export MONGODB_EXTRA_DATABASES_FILE="" + export MONGODB_EXTRA_PASSWORDS_FILE="" + fi + + exec /opt/bitnami/scripts/mongodb/entrypoint.sh /opt/bitnami/scripts/mongodb/run.sh + setup-hidden.sh: |- + #!/bin/bash + + . /opt/bitnami/scripts/mongodb-env.sh + + {{- if .Values.externalAccess.hidden.enabled }} + {{- if eq .Values.externalAccess.hidden.service.type "LoadBalancer" }} + {{- if .Values.externalAccess.autoDiscovery.enabled }} + export MONGODB_ADVERTISED_HOSTNAME="$(<${SHARED_FILE})" + {{- else }} + ID="${MY_POD_NAME#"{{ $fullname }}-hidden-"}" + export MONGODB_ADVERTISED_HOSTNAME=$(echo '{{ .Values.externalAccess.hidden.service.loadBalancerIPs }}' | tr -d '[]' | cut -d ' ' -f "$(($ID + 1))") + {{- end }} + {{- else if eq .Values.externalAccess.hidden.service.type "NodePort" }} + ID="${MY_POD_NAME#"{{ $fullname }}-hidden-"}" + if is_empty_value "$MONGODB_ADVERTISED_PORT_NUMBER"; then + export MONGODB_ADVERTISED_PORT_NUMBER=$(echo '{{ .Values.externalAccess.service.nodePorts }}' | tr -d '[]' | cut -d ' ' -f "$(($ID + 1))") + fi + {{- if .Values.externalAccess.hidden.service.domain }} + export MONGODB_ADVERTISED_HOSTNAME={{ .Values.externalAccess.hidden.service.domain }} + {{- else }} + export MONGODB_ADVERTISED_HOSTNAME=$MY_POD_HOST_IP + {{- end }} + {{- end }} + {{- end }} + + {{- if .Values.replicaSetConfigurationSettings.enabled }} + # placed here before root password env is overwritten + # makes no assumption about starting state + # ensures that any stepDown or non-default starting state is handled + /scripts/replicaSetConfigurationSettings.sh & + {{- end }} + + echo "Advertised Hostname: $MONGODB_ADVERTISED_HOSTNAME" + echo "Advertised Port: $MONGODB_ADVERTISED_PORT_NUMBER" + echo "Configuring node as a hidden node" + export MONGODB_REPLICA_SET_MODE="hidden" + export MONGODB_INITIAL_PRIMARY_ROOT_USER="$MONGODB_ROOT_USER" + export MONGODB_INITIAL_PRIMARY_ROOT_PASSWORD="$MONGODB_ROOT_PASSWORD" + export MONGODB_INITIAL_PRIMARY_PORT_NUMBER="$MONGODB_PORT_NUMBER" + export MONGODB_ROOT_PASSWORD="" + export MONGODB_EXTRA_USERNAMES="" + export MONGODB_EXTRA_DATABASES="" + export MONGODB_EXTRA_PASSWORDS="" + export MONGODB_ROOT_PASSWORD_FILE="" + export MONGODB_EXTRA_USERNAMES_FILE="" + export MONGODB_EXTRA_DATABASES_FILE="" + export MONGODB_EXTRA_PASSWORDS_FILE="" + exec /opt/bitnami/scripts/mongodb/entrypoint.sh /opt/bitnami/scripts/mongodb/run.sh + {{- if .Values.replicaSetConfigurationSettings.enabled }} + replicaSetConfigurationSettings.sh: |- + #!/bin/bash + # This script to be called when pod starts. + # This script sets rs settings which can not be applied via conf file + + function logger () + #$1 is the line to be logged + { + echo "replicaSetConfigurationSettings.sh -- ${1}" >&1 + } + + SLEEP_PERIOD=10 + + {{- if and .Values.auth.enabled .Values.auth.rootPassword }} + usernameAndPassword="-u root -p ${MONGODB_ROOT_PASSWORD}" + {{- else }} + usernameAndPassword="" + {{- end }} + + # load Values.replicaSetConfigurationSettings.configuration into associtive array which makes iterating and string manipulation easy + declare -A desiredRsConf + {{ range $setting, $value := .Values.replicaSetConfigurationSettings.configuration -}} + {{ printf "desiredRsConf[%s]='%v'" $setting $value }} + {{ end }} + + rsConfWriteAttempts=0 + rs_conf_configured_ok=unknown + + while [[ "${rs_conf_configured_ok}" != "true" ]]; do + + # give the rs setup a chance to succeed before attempting to read or configure + sleep ${SLEEP_PERIOD} + + counter=0 + while ! mongosh ${usernameAndPassword} --eval 'rs.conf()'; do + counter=$((${counter} +1)) + logger "not yet able to read rs.conf settings from the currently running rs (after ${counter} attempts)" + sleep ${SLEEP_PERIOD} + done + counter=$((${counter} +1)) + logger "rs.conf settings have been read from the currently running rs (after ${counter} attempts)" + + # read rs.conf again and store it. settings format is '"" : ,' + currentRsConf=$(mongosh ${usernameAndPassword} --eval 'rs.conf()') + + desiredEqualsactual=unknown + settingsToConfigure="" + for key in ${!desiredRsConf[@]}; do + value=${desiredRsConf[$key]} + if ! $(echo "\"${currentRsConf}"\" | grep -q -e "${key}: ${value},"); then + logger "rs conf setting: ${key} value will be set to: ${value}" + settingsToConfigure="${settingsToConfigure}cfg.settings.${key} = ${value}; " + desiredEqualsactual=false + else + logger "rs conf: ${key} is already at desired value: ${value}" + fi + done + + if [[ "${desiredEqualsactual}" != "false" ]]; then + logger "replicaSetConfigurationSettings match the settings of the currently running rs" + desiredEqualsactual=true + rs_conf_configured_ok=true + logger "Current settings match desired settings (There have been ${rsConfWriteAttempts} attempts to write to mongoDB rs configuration)" + exit + fi + + # apply the settings only if this member is currently the mongo replicaset PRIMARY + # it might take a little time before any pod is PRIMARY + isMaster=unknown + if ! mongosh ${usernameAndPassword} --eval 'rs.isMaster()' | grep -q "ismaster: true"; then + isMaster=false + logger "This node is not yet PRIMARY - replicaSetConfigurationSettings will only be set on the member that is currently PRIMARY" + else + isMaster=true + logger "This node is PRIMARY" + fi + + if [[ "${isMaster}" == "true" ]]; then + logger "This node is currently PRIMARY - will apply rs.conf settings" + + # avoiding tricky string substitution with single quotes by making the eval string a set of vars + rsconf="cfg = rs.conf();" + rsreconf="rs.reconfig(cfg);" + rsCommand="${rsconf} ${settingsToConfigure} ${rsreconf}" + + mongosh ${usernameAndPassword} --eval "${rsCommand}" + if [ $? -ne 0 ]; then + logger "Failed to apply mongodb cfg.settings configuration" + else + logger "mongodb replicaset cfg.settings configuration applied" + logger "Will check rs conf" + # don't exit just yet - the settings will be checked in the next loop + fi + rsConfWriteAttempts=$((${rsConfWriteAttempts} + 1 )) + fi + done + {{- end }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/replicaset/statefulset.yaml b/deployment/charts/mongodb/templates/replicaset/statefulset.yaml new file mode 100644 index 0000000..ecfe3cf --- /dev/null +++ b/deployment/charts/mongodb/templates/replicaset/statefulset.yaml @@ -0,0 +1,563 @@ +{{- if eq .Values.architecture "replicaset" }} +{{- $replicaCount := int .Values.replicaCount }} +{{- $loadBalancerIPListLength := len .Values.externalAccess.service.loadBalancerIPs }} +{{- if not (and .Values.externalAccess.enabled (not .Values.externalAccess.autoDiscovery.enabled) (not (eq $replicaCount $loadBalancerIPListLength )) (eq .Values.externalAccess.service.type "LoadBalancer")) }} +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ include "mongodb.fullname" . }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: mongodb + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.labels }} + {{- include "common.tplvalues.render" (dict "value" .Values.labels "context" $) | nindent 4 }} + {{- end }} + {{- if or .Values.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + serviceName: {{ include "mongodb.service.nameOverride" . }} + podManagementPolicy: {{ .Values.podManagementPolicy }} + replicas: {{ .Values.replicaCount }} + {{- if .Values.updateStrategy }} + updateStrategy: {{- toYaml .Values.updateStrategy | nindent 4 }} + {{- end }} + selector: + matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: mongodb + template: + metadata: + labels: {{- include "common.labels.standard" . | nindent 8 }} + app.kubernetes.io/component: mongodb + {{- if .Values.podLabels }} + {{- include "common.tplvalues.render" (dict "value" .Values.podLabels "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 8 }} + {{- end }} + {{- if or (include "mongodb.createConfigmap" .) .Values.podAnnotations }} + annotations: + {{- if (include "mongodb.createConfigmap" .) }} + checksum/configuration: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- end }} + {{- if .Values.podAnnotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.podAnnotations "context" $) | nindent 8 }} + {{- end }} + {{- end }} + spec: + {{- include "mongodb.imagePullSecrets" . | nindent 6 }} + {{- if .Values.schedulerName }} + schedulerName: {{ .Values.schedulerName | quote }} + {{- end }} + serviceAccountName: {{ template "mongodb.serviceAccountName" . }} + {{- if .Values.hostAliases }} + hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.hostAliases "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAffinityPreset "component" "mongodb" "topologyKey" .Values.topologyKey "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset "component" "mongodb" "topologyKey" .Values.topologyKey "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.nodeAffinityPreset.type "key" .Values.nodeAffinityPreset.key "values" .Values.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.tolerations "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.topologySpreadConstraints }} + topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.topologySpreadConstraints "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName }} + {{- end }} + {{- if .Values.runtimeClassName }} + runtimeClassName: {{ .Values.runtimeClassName }} + {{- end }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{ if .Values.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} + {{- end }} + {{- if or .Values.initContainers (and .Values.volumePermissions.enabled .Values.persistence.enabled) (and .Values.externalAccess.enabled .Values.externalAccess.autoDiscovery.enabled) .Values.tls.enabled }} + initContainers: + {{- if .Values.initContainers }} + {{- include "common.tplvalues.render" (dict "value" .Values.initContainers "context" $) | nindent 8 }} + {{- end }} + {{- if and .Values.volumePermissions.enabled .Values.persistence.enabled }} + - name: volume-permissions + image: {{ include "mongodb.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + command: + - /bin/bash + args: + - -ec + - | + mkdir -p {{ printf "%s/%s" .Values.persistence.mountPath (default "" .Values.persistence.subPath) }} + chown {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} {{ printf "%s/%s" .Values.persistence.mountPath (default "" .Values.persistence.subPath) }} + find {{ printf "%s/%s" .Values.persistence.mountPath (default "" .Values.persistence.subPath) }} -mindepth 1 -maxdepth 1 -not -name ".snapshot" -not -name "lost+found" | xargs -r chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + securityContext: {{- omit .Values.volumePermissions.securityContext "runAsUser" | toYaml | nindent 12 }} + {{- else }} + securityContext: {{- .Values.volumePermissions.securityContext | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.volumePermissions.resources }} + resources: {{- toYaml .Values.volumePermissions.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: datadir + mountPath: {{ .Values.persistence.mountPath }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: generate-tls-certs + image: {{ include "mongodb.tls.image" . }} + imagePullPolicy: {{ .Values.tls.image.pullPolicy | quote }} + env: + - name: MY_POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: MY_POD_HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + volumeMounts: + {{- if (include "mongodb.autoGenerateCerts" .) }} + - name: certs-volume + mountPath: /certs/CAs + {{- else }} + {{- range $index, $_ := .Values.tls.replicaset.existingSecrets }} + - name: mongodb-certs-{{ $index }} + mountPath: /certs-{{ $index }} + {{- end }} + {{- end }} + - name: certs + mountPath: /certs + - name: common-scripts + mountPath: /bitnami/scripts + command: + - /bitnami/scripts/generate-certs.sh + args: + - -s {{ include "mongodb.service.nameOverride" . }} + {{- if .Values.externalAccess.service.loadBalancerIPs }} + - -i {{ join "," .Values.externalAccess.service.loadBalancerIPs }} + {{- end }} + {{- if .Values.tls.extraDnsNames }} + - -n {{ join "," .Values.tls.extraDnsNames }} + {{- end }} + {{- if .Values.tls.resources }} + resources: {{- toYaml .Values.tls.resources | nindent 12 }} + {{- end }} + {{- end }} + {{- if and .Values.externalAccess.enabled .Values.externalAccess.autoDiscovery.enabled (eq .Values.externalAccess.service.type "LoadBalancer") }} + - name: auto-discovery + image: {{ include "mongodb.externalAccess.autoDiscovery.image" . }} + imagePullPolicy: {{ .Values.externalAccess.autoDiscovery.image.pullPolicy | quote }} + command: + - /scripts/auto-discovery.sh + env: + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: SHARED_FILE + value: "/shared/info.txt" + {{- if .Values.externalAccess.autoDiscovery.resources }} + resources: {{- toYaml .Values.externalAccess.autoDiscovery.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: shared + mountPath: /shared + - name: scripts + mountPath: /scripts/auto-discovery.sh + subPath: auto-discovery.sh + {{- end }} + {{- end }} + containers: + - name: mongodb + image: {{ include "mongodb.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy | quote }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.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.command }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.command "context" $) | nindent 12 }} + {{- else }} + command: + - /scripts/setup.sh + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} + {{- else if .Values.args }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.args "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.lifecycleHooks }} + lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.lifecycleHooks "context" $) | nindent 12 }} + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" (or .Values.image.debug .Values.diagnosticMode.enabled) | quote }} + {{- if and .Values.externalAccess.enabled .Values.externalAccess.autoDiscovery.enabled (eq .Values.externalAccess.service.type "LoadBalancer") }} + - name: SHARED_FILE + value: "/shared/info.txt" + {{- end }} + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: MY_POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: MY_POD_HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: K8S_SERVICE_NAME + value: "{{ include "mongodb.service.nameOverride" . }}" + - name: MONGODB_INITIAL_PRIMARY_HOST + value: {{ printf "%s-0.$(K8S_SERVICE_NAME).$(MY_POD_NAMESPACE).svc.%s" (include "mongodb.fullname" .) .Values.clusterDomain }} + - name: MONGODB_REPLICA_SET_NAME + value: {{ .Values.replicaSetName | quote }} + {{- if and .Values.replicaSetHostnames (not .Values.externalAccess.enabled) }} + - name: MONGODB_ADVERTISED_HOSTNAME + value: "$(MY_POD_NAME).$(K8S_SERVICE_NAME).$(MY_POD_NAMESPACE).svc.{{ .Values.clusterDomain }}" + {{- end }} + {{- $customUsers := include "mongodb.customUsers" . -}} + {{- $customDatabases := include "mongodb.customDatabases" . -}} + {{- if not (empty $customUsers) }} + - name: MONGODB_EXTRA_USERNAMES + value: {{ $customUsers | quote }} + {{- end }} + {{- if not (empty $customDatabases) }} + - name: MONGODB_EXTRA_DATABASES + value: {{ $customDatabases | quote }} + {{- end }} + {{- if .Values.auth.enabled }} + {{- if and (not (empty $customUsers)) (not (empty $customDatabases)) }} + - name: MONGODB_EXTRA_PASSWORDS + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-passwords + {{- end }} + - name: MONGODB_ROOT_USER + value: {{ .Values.auth.rootUser | quote }} + - name: MONGODB_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-root-password + - name: MONGODB_REPLICA_SET_KEY + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-replica-set-key + {{- end }} + {{- if and .Values.metrics.enabled (not (empty .Values.metrics.username)) }} + - name: MONGODB_METRICS_USERNAME + value: {{ .Values.metrics.username | quote }} + {{- if .Values.auth.enabled }} + - name: MONGODB_METRICS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-metrics-password + {{- end }} + {{- end }} + - name: ALLOW_EMPTY_PASSWORD + value: {{ ternary "no" "yes" .Values.auth.enabled | quote }} + - name: MONGODB_SYSTEM_LOG_VERBOSITY + value: {{ .Values.systemLogVerbosity | quote }} + - name: MONGODB_DISABLE_SYSTEM_LOG + value: {{ ternary "yes" "no" .Values.disableSystemLog | quote }} + - name: MONGODB_DISABLE_JAVASCRIPT + value: {{ ternary "yes" "no" .Values.disableJavascript | quote }} + - name: MONGODB_ENABLE_JOURNAL + value: {{ ternary "yes" "no" .Values.enableJournal | quote }} + - name: MONGODB_PORT_NUMBER + value: {{ .Values.containerPorts.mongodb | quote }} + - name: MONGODB_ENABLE_IPV6 + value: {{ ternary "yes" "no" .Values.enableIPv6 | quote }} + - name: MONGODB_ENABLE_DIRECTORY_PER_DB + value: {{ ternary "yes" "no" .Values.directoryPerDB | quote }} + {{- $extraFlags := .Values.extraFlags | join " " -}} + {{- if .Values.tls.enabled }} + {{- $extraFlags = printf "--tlsMode=%s --tlsCertificateKeyFile=/certs/mongodb.pem --tlsCAFile=/certs/mongodb-ca-cert %s" .Values.tls.mode $extraFlags }} + {{- end }} + {{- if ne $extraFlags "" }} + - name: MONGODB_EXTRA_FLAGS + value: {{ $extraFlags | quote }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: MONGODB_CLIENT_EXTRA_FLAGS + value: --tls --tlsCertificateKeyFile=/certs/mongodb.pem --tlsCAFile=/certs/mongodb-ca-cert + {{- end }} + {{- if .Values.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + {{- if or .Values.extraEnvVarsCM .Values.extraEnvVarsSecret }} + envFrom: + {{- if .Values.extraEnvVarsCM }} + - configMapRef: + name: {{ tpl .Values.extraEnvVarsCM . | quote }} + {{- end }} + {{- if .Values.extraEnvVarsSecret }} + - secretRef: + name: {{ tpl .Values.extraEnvVarsSecret . | quote }} + {{- end }} + {{- end }} + ports: + - name: mongodb + containerPort: {{ .Values.containerPorts.mongodb }} + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customLivenessProbe "context" $) | nindent 12 }} + {{- else if .Values.livenessProbe.enabled }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.livenessProbe "enabled") "context" $) | nindent 12 }} + exec: + command: + - /bitnami/scripts/ping-mongodb.sh + {{- end }} + {{- if .Values.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 12 }} + {{- else if .Values.readinessProbe.enabled }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.readinessProbe "enabled") "context" $) | nindent 12 }} + exec: + command: + - /bitnami/scripts/readiness-probe.sh + {{- end }} + {{- if .Values.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.startupProbe.enabled }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.startupProbe "enabled") "context" $) | nindent 12 }} + exec: + command: + - /bitnami/scripts/startup-probe.sh + {{- end }} + {{- end }} + {{- if .Values.resources }} + resources: {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: datadir + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + - name: common-scripts + mountPath: /bitnami/scripts + {{- if or .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + mountPath: /docker-entrypoint-initdb.d + {{- end }} + {{- if or .Values.configuration .Values.existingConfigmap }} + - name: config + mountPath: /opt/bitnami/mongodb/conf/mongodb.conf + subPath: mongodb.conf + {{- end }} + - name: scripts + mountPath: /scripts/setup.sh + subPath: setup.sh + {{ if .Values.replicaSetConfigurationSettings.enabled }} + - name: scripts + mountPath: /scripts/replicaSetConfigurationSettings.sh + subPath: replicaSetConfigurationSettings.sh + {{- end }} + {{- if and .Values.externalAccess.enabled .Values.externalAccess.autoDiscovery.enabled (eq .Values.externalAccess.service.type "LoadBalancer") }} + - name: shared + mountPath: /shared + {{- end }} + {{- if .Values.tls.enabled }} + - name: certs + mountPath: /certs + {{- end }} + {{- if .Values.extraVolumeMounts }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraVolumeMounts "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.metrics.enabled }} + - name: metrics + image: {{ template "mongodb.metrics.image" . }} + imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.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.metrics.command }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.command "context" $) | nindent 12 }} + {{- else }} + command: + - /bin/bash + - -ec + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} + {{- else if .Values.metrics.args }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.args "context" $) | nindent 12 }} + {{- else }} + args: + - | + /bin/mongodb_exporter --collect-all --compatible-mode --web.listen-address ":{{ .Values.metrics.containerPort }}" --mongodb.uri "{{ include "mongodb.mongodb_exporter.uri" . }}" {{ .Values.metrics.extraFlags }} + {{- end }} + env: + {{- if .Values.auth.enabled }} + {{- if not .Values.metrics.username }} + - name: MONGODB_ROOT_USER + value: {{ .Values.auth.rootUser | quote }} + - name: MONGODB_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-root-password + {{- else }} + - name: MONGODB_METRICS_USERNAME + value: {{ .Values.metrics.username | quote }} + - name: MONGODB_METRICS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-metrics-password + {{- end }} + {{- end }} + volumeMounts: + {{- if .Values.tls.enabled }} + - name: certs + mountPath: /certs + {{- end }} + ports: + - name: metrics + containerPort: {{ .Values.metrics.containerPort }} + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.metrics.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customLivenessProbe "context" $) | nindent 12 }} + {{- else if .Values.metrics.livenessProbe.enabled }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.livenessProbe "enabled") "context" $) | nindent 12 }} + httpGet: + path: /metrics + port: metrics + {{- end }} + {{- if .Values.metrics.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customReadinessProbe "context" $) | nindent 12 }} + {{- else if .Values.metrics.readinessProbe.enabled }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.readinessProbe "enabled") "context" $) | nindent 12 }} + httpGet: + path: /metrics + port: metrics + {{- end }} + {{- if .Values.metrics.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.metrics.startupProbe.enabled }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.startupProbe "enabled") "context" $) | nindent 12 }} + tcpSocket: + port: metrics + {{- end }} + {{- end }} + {{- if .Values.metrics.resources }} + resources: {{- toYaml .Values.metrics.resources | nindent 12 }} + {{- end }} + {{- end }} + {{- if .Values.sidecars }} + {{- include "common.tplvalues.render" (dict "value" .Values.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + - name: common-scripts + configMap: + name: {{ printf "%s-common-scripts" (include "mongodb.fullname" .) }} + defaultMode: 0550 + {{- if or .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + configMap: + name: {{ template "mongodb.initdbScriptsCM" . }} + {{- end }} + {{- if or .Values.configuration .Values.existingConfigmap }} + - name: config + configMap: + name: {{ include "mongodb.configmapName" . }} + {{- end }} + {{- if and .Values.externalAccess.enabled .Values.externalAccess.autoDiscovery.enabled (eq .Values.externalAccess.service.type "LoadBalancer") }} + - name: shared + emptyDir: {} + {{- end }} + - name: scripts + configMap: + name: {{ printf "%s-scripts" (include "mongodb.fullname" .) }} + defaultMode: 0755 + {{- if .Values.extraVolumes }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraVolumes "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: certs + emptyDir: {} + {{- if (include "mongodb.autoGenerateCerts" .) }} + - name: certs-volume + secret: + secretName: {{ template "mongodb.tlsSecretName" . }} + items: + - key: mongodb-ca-cert + path: mongodb-ca-cert + mode: 0600 + - key: mongodb-ca-key + path: mongodb-ca-key + mode: 0600 + {{- else }} + {{- range $index, $secret := .Values.tls.replicaset.existingSecrets }} + - name: mongodb-certs-{{ $index }} + secret: + secretName: {{ include "common.tplvalues.render" ( dict "value" $secret "context" $) }} + defaultMode: 256 + {{- end }} + {{- end }} + {{- end }} + {{- if not .Values.persistence.enabled }} + - name: datadir + {{- if .Values.persistence.medium }} + emptyDir: + medium: {{ .Values.persistence.medium | quote }} + {{- else }} + emptyDir: {} + {{- end }} + {{- else }} + volumeClaimTemplates: + - metadata: + name: datadir + {{- if .Values.persistence.annotations }} + annotations: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.annotations "context" $) | nindent 10 }} + {{- end }} + spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{- if .Values.persistence.volumeClaimTemplates.requests }} + {{- include "common.tplvalues.render" (dict "value" .Values.persistence.volumeClaimTemplates.requests "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.persistence.volumeClaimTemplates.dataSource }} + dataSource: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.volumeClaimTemplates.dataSource "context" $) | nindent 10 }} + {{- end }} + {{- if .Values.persistence.volumeClaimTemplates.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.volumeClaimTemplates.selector "context" $) | nindent 10 }} + {{- end }} + {{ include "common.storage.class" (dict "persistence" .Values.persistence "global" .Values.global) }} + {{- end }} +{{- end }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/replicaset/svc.yaml b/deployment/charts/mongodb/templates/replicaset/svc.yaml new file mode 100644 index 0000000..2d1e779 --- /dev/null +++ b/deployment/charts/mongodb/templates/replicaset/svc.yaml @@ -0,0 +1,43 @@ +{{- if and (eq .Values.architecture "replicaset") .Values.externalAccess.enabled (eq .Values.externalAccess.service.type "ClusterIP") }} + +{{- $fullName := include "mongodb.fullname" . }} +{{- $replicaCount := .Values.replicaCount | int }} +{{- $root := . }} + +{{- range $i, $e := until $replicaCount }} +{{- $targetPod := printf "%s-%d" (printf "%s" $fullName) $i }} +{{- $_ := set $ "targetPod" $targetPod }} +apiVersion: v1 +kind: Service +metadata: + name: {{ printf "%s-%d" $fullName $i }} + namespace: {{ include "mongodb.namespace" $ }} + labels: {{- include "common.labels.standard" $ | nindent 4 }} + app.kubernetes.io/component: mongodb + {{- if $root.Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" $root.Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if or $root.Values.service.annotations $root.Values.commonAnnotations }} + annotations: + {{- if $root.Values.service.annotations }} + {{- include "common.tplvalues.render" ( dict "value" $root.Values.service.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if $root.Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" $root.Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: ClusterIP + ports: + - name: {{ $root.Values.service.portName | quote }} + port: {{ $root.Values.service.ports.mongodb }} + targetPort: mongodb + {{- if $root.Values.service.extraPorts }} + {{- include "common.tplvalues.render" (dict "value" $root.Values.service.extraPorts "context" $) | nindent 4 }} + {{- end }} + selector: {{- include "common.labels.matchLabels" $ | nindent 4 }} + app.kubernetes.io/component: mongodb + statefulset.kubernetes.io/pod-name: {{ $targetPod }} +--- +{{- end }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/role.yaml b/deployment/charts/mongodb/templates/role.yaml new file mode 100644 index 0000000..5630043 --- /dev/null +++ b/deployment/charts/mongodb/templates/role.yaml @@ -0,0 +1,30 @@ +{{- if .Values.rbac.create }} +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +kind: Role +metadata: + name: {{ include "mongodb.fullname" . }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} +rules: + - apiGroups: + - "" + resources: + - services + verbs: + - get + - list + - watch +{{- if .Values.rbac.rules }} +{{- include "common.tplvalues.render" ( dict "value" .Values.rbac.rules "context" $ ) | nindent 2 }} +{{- end -}} +{{- $pspAvailable := (semverCompare "<1.25-0" (include "common.capabilities.kubeVersion" .)) -}} +{{- if and $pspAvailable .Values.podSecurityPolicy.create }} + - apiGroups: ['{{ template "podSecurityPolicy.apiGroup" . }}'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: [{{ include "mongodb.fullname" . }}] +{{- end -}} +{{- end }} diff --git a/deployment/charts/mongodb/templates/rolebinding.yaml b/deployment/charts/mongodb/templates/rolebinding.yaml new file mode 100644 index 0000000..8950f8b --- /dev/null +++ b/deployment/charts/mongodb/templates/rolebinding.yaml @@ -0,0 +1,19 @@ +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +kind: RoleBinding +metadata: + name: {{ include "mongodb.fullname" . }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} +roleRef: + kind: Role + name: {{ include "mongodb.fullname" . }} + apiGroup: rbac.authorization.k8s.io +subjects: + - kind: ServiceAccount + name: {{ include "mongodb.serviceAccountName" . }} + namespace: {{ include "mongodb.namespace" . | quote }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/secrets-ca.yaml b/deployment/charts/mongodb/templates/secrets-ca.yaml new file mode 100644 index 0000000..95d3730 --- /dev/null +++ b/deployment/charts/mongodb/templates/secrets-ca.yaml @@ -0,0 +1,35 @@ +{{- if (include "mongodb.createTlsSecret" .) }} +{{- $fullname := include "mongodb.fullname" . }} +{{- $releaseNamespace := .Release.Namespace }} +{{- $clusterDomain := .Values.clusterDomain }} +{{- $cn := printf "%s.%s.svc.%s" $fullname .Release.Namespace $clusterDomain }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "mongodb.tlsSecretName" . }} + namespace: {{ template "mongodb.namespace" . }} + labels: + {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: mongodb + {{- 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 or .Values.tls.caCert .Values.tls.caKey (not .Values.tls.autoGenerated) }} + {{- $ca := buildCustomCert (required "A valid .Values.tls.caCert is required!" .Values.tls.caCert) (required "A valid .Values.tls.caKey is required!" .Values.tls.caKey) }} + {{- $cert := genSignedCert $cn nil nil 3650 $ca }} + {{- $pem := printf "%s%s" $cert.Cert $cert.Key }} + mongodb-ca-cert: {{ b64enc $ca.Cert }} + mongodb-ca-key: {{ b64enc $ca.Key }} + {{- else }} + {{- $ca:= genCA "myMongo-ca" 3650 }} + {{- $cert := genSignedCert $cn nil nil 3650 $ca }} + {{- $pem := printf "%s%s" $cert.Cert $cert.Key }} + mongodb-ca-cert: {{ b64enc $ca.Cert }} + mongodb-ca-key: {{ b64enc $ca.Key }} + {{- end }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/secrets.yaml b/deployment/charts/mongodb/templates/secrets.yaml new file mode 100644 index 0000000..acf8c48 --- /dev/null +++ b/deployment/charts/mongodb/templates/secrets.yaml @@ -0,0 +1,41 @@ +{{- if (include "mongodb.createSecret" .) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "mongodb.fullname" . }} + namespace: {{ template "mongodb.namespace" . }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: mongodb + {{- 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: + mongodb-root-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "mongodb.fullname" .) "key" "mongodb-root-password" "providedValues" (list "auth.rootPassword" ) "context" $) }} + {{- $customUsers := include "mongodb.customUsers" . -}} + {{- $customDatabases := include "mongodb.customDatabases" . -}} + {{- $customPasswords := include "mongodb.customPasswords" . -}} + {{- $passwordList := list -}} + {{- if and (not (empty $customUsers)) (not (empty $customDatabases)) -}} + {{- if not (empty $customPasswords) -}} + {{- $passwordList = $customPasswords -}} + {{- else -}} + {{- $customUsersList := splitList "," $customUsers -}} + {{- $customPasswordsList := list -}} + {{- range $customUsersList -}} + {{- $customPasswordsList = append $customPasswordsList (randAlphaNum 10) -}} + {{- end -}} + {{- $passwordList = (join "," $customPasswordsList) -}} + {{- end }} + mongodb-passwords: {{ include "common.secrets.passwords.manage" (dict "secret" (include "mongodb.fullname" .) "key" "mongodb-passwords" "providedValues" (list "mongodbPasswords") "context" (set (deepCopy $) "Values" (dict "mongodbPasswords" $passwordList))) }} + {{- end }} + {{- if .Values.metrics.username }} + mongodb-metrics-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "mongodb.fullname" .) "key" "mongodb-metrics-password" "providedValues" (list "metrics.password" ) "context" $) }} + {{- end }} + {{- if eq .Values.architecture "replicaset" }} + mongodb-replica-set-key: {{ include "common.secrets.passwords.manage" (dict "secret" (include "mongodb.fullname" .) "key" "mongodb-replica-set-key" "providedValues" (list "auth.replicaSetKey" ) "context" $) }} + {{- end }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/serviceaccount.yaml b/deployment/charts/mongodb/templates/serviceaccount.yaml new file mode 100644 index 0000000..f4aa81a --- /dev/null +++ b/deployment/charts/mongodb/templates/serviceaccount.yaml @@ -0,0 +1,23 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "mongodb.serviceAccountName" . }} + namespace: {{ include "mongodb.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 or .Values.serviceAccount.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.serviceAccount.annotations }} + {{ toYaml .Values.serviceAccount.annotations | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +secrets: + - name: {{ template "mongodb.fullname" . }} +automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/servicemonitor.yaml b/deployment/charts/mongodb/templates/servicemonitor.yaml new file mode 100644 index 0000000..0a00f71 --- /dev/null +++ b/deployment/charts/mongodb/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 "mongodb.fullname" . }} + namespace: {{ include "mongodb.serviceMonitor.namespace" . }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.metrics.serviceMonitor.labels }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.serviceMonitor.labels "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + app.kubernetes.io/component: metrics + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- if .Values.metrics.serviceMonitor.jobLabel }} + jobLabel: {{ .Values.metrics.serviceMonitor.jobLabel }} + {{- end }} + 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 }} + app.kubernetes.io/component: metrics + endpoints: + - port: http-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.relabelings }} + relabelings: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.relabelings "context" $) | nindent 8 }} + {{- 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.honorLabels }} + honorLabels: {{ .Values.metrics.serviceMonitor.honorLabels }} + {{- end }} + namespaceSelector: + matchNames: + - "{{ include "mongodb.namespace" . }}" +{{- end }} diff --git a/deployment/charts/mongodb/templates/standalone/dep-sts.yaml b/deployment/charts/mongodb/templates/standalone/dep-sts.yaml new file mode 100644 index 0000000..6b7db0c --- /dev/null +++ b/deployment/charts/mongodb/templates/standalone/dep-sts.yaml @@ -0,0 +1,486 @@ +{{- if not (eq .Values.architecture "replicaset") }} +apiVersion: {{ if .Values.useStatefulSet }}{{ include "common.capabilities.statefulset.apiVersion" . }}{{- else }}{{ include "common.capabilities.deployment.apiVersion" . }}{{- end }} +kind: {{ if .Values.useStatefulSet }}StatefulSet{{- else }}Deployment{{- end }} +metadata: + name: {{ include "mongodb.fullname" . }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: mongodb + {{- if .Values.labels }} + {{- include "common.tplvalues.render" (dict "value" .Values.labels "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if or .Values.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + replicas: 1 + {{- if .Values.useStatefulSet }} + serviceName: {{ include "mongodb.fullname" . }} + {{- end }} + {{- if .Values.updateStrategy}} + {{- if .Values.useStatefulSet }} + updateStrategy: + {{- else }} + strategy: + {{- end }} + {{- toYaml .Values.updateStrategy | nindent 4 }} + {{- end}} + selector: + matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: mongodb + template: + metadata: + labels: {{- include "common.labels.standard" . | nindent 8 }} + app.kubernetes.io/component: mongodb + {{- if .Values.podLabels }} + {{- include "common.tplvalues.render" (dict "value" .Values.podLabels "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 8 }} + {{- end }} + {{- if or (include "mongodb.createConfigmap" .) .Values.podAnnotations }} + annotations: + {{- if (include "mongodb.createConfigmap" .) }} + checksum/configuration: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- end }} + {{- if .Values.podAnnotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.podAnnotations "context" $) | nindent 8 }} + {{- end }} + {{- end }} + spec: + {{- include "mongodb.imagePullSecrets" . | nindent 6 }} + {{- if .Values.hostAliases }} + hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.hostAliases "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.schedulerName }} + schedulerName: {{ .Values.schedulerName | quote }} + {{- end }} + serviceAccountName: {{ template "mongodb.serviceAccountName" . }} + {{- if .Values.affinity }} + affinity: {{- include "common.tplvalues.render" (dict "value" .Values.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAffinityPreset "component" "mongodb" "topologyKey" .Values.topologyKey "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset "component" "mongodb" "topologyKey" .Values.topologyKey "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.nodeAffinityPreset.type "key" .Values.nodeAffinityPreset.key "values" .Values.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.hostAliases }} + hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.hostAliases "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.tolerations "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName }} + {{- end }} + {{- if .Values.runtimeClassName }} + runtimeClassName: {{ .Values.runtimeClassName }} + {{- end }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{ if .Values.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} + {{- end }} + {{- if or .Values.initContainers (and .Values.volumePermissions.enabled .Values.persistence.enabled) .Values.tls.enabled }} + initContainers: + {{- if .Values.initContainers }} + {{- include "common.tplvalues.render" (dict "value" .Values.initContainers "context" $) | nindent 8 }} + {{- end }} + {{- if and .Values.volumePermissions.enabled .Values.persistence.enabled }} + - name: volume-permissions + image: {{ include "mongodb.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + command: + - /bin/bash + args: + - -ec + - | + mkdir -p {{ printf "%s/%s" .Values.persistence.mountPath (default "" .Values.persistence.subPath) }} + chown {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} {{ printf "%s/%s" .Values.persistence.mountPath (default "" .Values.persistence.subPath) }} + find {{ printf "%s/%s" .Values.persistence.mountPath (default "" .Values.persistence.subPath) }} -mindepth 1 -maxdepth 1 -not -name ".snapshot" -not -name "lost+found" | xargs -r chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + securityContext: {{- omit .Values.volumePermissions.securityContext "runAsUser" | toYaml | nindent 12 }} + {{- else }} + securityContext: {{- .Values.volumePermissions.securityContext | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.volumePermissions.resources }} + resources: {{- toYaml .Values.volumePermissions.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: datadir + mountPath: {{ .Values.persistence.mountPath }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: generate-tls-certs + image: {{ include "mongodb.tls.image" . }} + imagePullPolicy: {{ .Values.tls.image.pullPolicy | quote }} + env: + - name: MY_POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: MY_POD_HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + volumeMounts: + {{- if (include "mongodb.autoGenerateCerts" .) }} + - name: certs-volume + mountPath: /certs/CAs + {{- else }} + - name: mongodb-certs-0 + mountPath: /certs-0 + {{- end }} + - name: certs + mountPath: /certs + - name: common-scripts + mountPath: /bitnami/scripts + command: + - /bitnami/scripts/generate-certs.sh + args: + - -s {{ include "mongodb.service.nameOverride" . }} + {{- if .Values.externalAccess.service.loadBalancerIPs }} + - -i {{ join "," .Values.externalAccess.service.loadBalancerIPs }} + {{- end }} + {{- if .Values.tls.extraDnsNames }} + - -n {{ join "," .Values.tls.extraDnsNames }} + {{- end }} + {{- if .Values.tls.resources }} + resources: {{- toYaml .Values.tls.resources | nindent 12 }} + {{- end }} + {{- end }} + {{- end }} + containers: + - name: mongodb + image: {{ include "mongodb.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy | quote }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.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.command }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.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.args }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.args "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.lifecycleHooks }} + lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.lifecycleHooks "context" $) | nindent 12 }} + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" (or .Values.image.debug .Values.diagnosticMode.enabled) | quote }} + {{- $customUsers := include "mongodb.customUsers" . -}} + {{- $customDatabases := include "mongodb.customDatabases" . -}} + {{- if not (empty $customUsers) }} + - name: MONGODB_EXTRA_USERNAMES + value: {{ $customUsers | quote }} + {{- end }} + {{- if not (empty $customDatabases) }} + - name: MONGODB_EXTRA_DATABASES + value: {{ $customDatabases | quote }} + {{- end }} + {{- if .Values.auth.enabled }} + {{- if and (not (empty $customUsers)) (not (empty $customDatabases)) }} + - name: MONGODB_EXTRA_PASSWORDS + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-passwords + {{- end }} + - name: MONGODB_ROOT_USER + value: {{ .Values.auth.rootUser | quote }} + - name: MONGODB_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-root-password + {{- end }} + {{- if and .Values.metrics.enabled (not (empty .Values.metrics.username)) }} + - name: MONGODB_METRICS_USERNAME + value: {{ .Values.metrics.username | quote }} + {{- if .Values.auth.enabled }} + - name: MONGODB_METRICS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-metrics-password + {{- end }} + {{- end }} + - name: ALLOW_EMPTY_PASSWORD + value: {{ ternary "no" "yes" .Values.auth.enabled | quote }} + - name: MONGODB_SYSTEM_LOG_VERBOSITY + value: {{ .Values.systemLogVerbosity | quote }} + - name: MONGODB_DISABLE_SYSTEM_LOG + value: {{ ternary "yes" "no" .Values.disableSystemLog | quote }} + - name: MONGODB_DISABLE_JAVASCRIPT + value: {{ ternary "yes" "no" .Values.disableJavascript | quote }} + - name: MONGODB_ENABLE_JOURNAL + value: {{ ternary "yes" "no" .Values.enableJournal | quote }} + - name: MONGODB_PORT_NUMBER + value: {{ .Values.containerPorts.mongodb | quote }} + - name: MONGODB_ENABLE_IPV6 + value: {{ ternary "yes" "no" .Values.enableIPv6 | quote }} + - name: MONGODB_ENABLE_DIRECTORY_PER_DB + value: {{ ternary "yes" "no" .Values.directoryPerDB | quote }} + {{- $extraFlags := .Values.extraFlags | join " " -}} + {{- if .Values.tls.enabled }} + {{- $extraFlags = printf "--tlsMode=%s --tlsCertificateKeyFile=/certs/mongodb.pem --tlsCAFile=/certs/mongodb-ca-cert %s" .Values.tls.mode $extraFlags }} + {{- end }} + {{- if ne $extraFlags "" }} + - name: MONGODB_EXTRA_FLAGS + value: {{ $extraFlags | quote }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: MONGODB_CLIENT_EXTRA_FLAGS + value: --tls --tlsCertificateKeyFile=/certs/mongodb.pem --tlsCAFile=/certs/mongodb-ca-cert + {{- end }} + {{- if .Values.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + {{- if or .Values.extraEnvVarsCM .Values.extraEnvVarsSecret }} + envFrom: + {{- if .Values.extraEnvVarsCM }} + - configMapRef: + name: {{ tpl .Values.extraEnvVarsCM . | quote }} + {{- end }} + {{- if .Values.extraEnvVarsSecret }} + - secretRef: + name: {{ tpl .Values.extraEnvVarsSecret . | quote }} + {{- end }} + {{- end }} + ports: + - name: mongodb + containerPort: {{ .Values.containerPorts.mongodb }} + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customLivenessProbe "context" $) | nindent 12 }} + {{- else if .Values.livenessProbe.enabled }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.livenessProbe "enabled") "context" $) | nindent 12 }} + exec: + command: + - /bitnami/scripts/ping-mongodb.sh + {{- end }} + {{- end }} + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 12 }} + {{- else if .Values.readinessProbe.enabled }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.readinessProbe "enabled") "context" $) | nindent 12 }} + exec: + command: + - /bitnami/scripts/readiness-probe.sh + {{- end }} + {{- end }} + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.startupProbe.enabled }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.startupProbe "enabled") "context" $) | nindent 12 }} + exec: + command: + - /bitnami/scripts/startup-probe.sh + {{- end }} + {{- end }} + {{- if .Values.resources }} + resources: {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: datadir + mountPath: {{ .Values.persistence.mountPath }} + subPath: {{ .Values.persistence.subPath }} + - name: common-scripts + mountPath: /bitnami/scripts + {{- if or .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + mountPath: /docker-entrypoint-initdb.d + {{- end }} + {{- if or .Values.configuration .Values.existingConfigmap }} + - name: config + mountPath: /opt/bitnami/mongodb/conf/mongodb.conf + subPath: mongodb.conf + {{- end }} + {{- if .Values.tls.enabled }} + - name: certs + mountPath: /certs + {{- end }} + {{- if .Values.extraVolumeMounts }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraVolumeMounts "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.metrics.enabled }} + - name: metrics + image: {{ template "mongodb.metrics.image" . }} + imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.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.metrics.command }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.command "context" $) | nindent 12 }} + {{- else }} + command: + - /bin/bash + - -ec + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} + {{- else if .Values.metrics.args }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.args "context" $) | nindent 12 }} + {{- else }} + args: + - | + /bin/mongodb_exporter --collect-all --compatible-mode --web.listen-address ":{{ .Values.metrics.containerPort }}" --mongodb.uri "{{ include "mongodb.mongodb_exporter.uri" . }}" {{ .Values.metrics.extraFlags }} + {{- end }} + env: + {{- if .Values.auth.enabled }} + {{- if not .Values.metrics.username }} + - name: MONGODB_ROOT_USER + value: {{ .Values.auth.rootUser | quote }} + - name: MONGODB_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-root-password + {{- else }} + - name: MONGODB_METRICS_USERNAME + value: {{ .Values.metrics.username | quote }} + - name: MONGODB_METRICS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mongodb.secretName" . }} + key: mongodb-metrics-password + {{- end }} + {{- end }} + volumeMounts: + {{- if .Values.tls.enabled }} + - name: certs + mountPath: /certs + {{- end }} + ports: + - name: metrics + containerPort: {{ .Values.metrics.containerPort }} + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.metrics.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customLivenessProbe "context" $) | nindent 12 }} + {{- else if .Values.metrics.livenessProbe.enabled }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.livenessProbe "enabled") "context" $) | nindent 12 }} + httpGet: + path: /metrics + port: metrics + {{- end }} + {{- if .Values.metrics.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customReadinessProbe "context" $) | nindent 12 }} + {{- else if .Values.metrics.readinessProbe.enabled }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.readinessProbe "enabled") "context" $) | nindent 12 }} + httpGet: + path: /metrics + port: metrics + {{- end }} + {{- if .Values.metrics.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.metrics.startupProbe.enabled }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.startupProbe "enabled") "context" $) | nindent 12 }} + tcpSocket: + port: metrics + {{- end }} + {{- end }} + {{- if .Values.metrics.resources }} + resources: {{- toYaml .Values.metrics.resources | nindent 12 }} + {{- end }} + {{- end }} + {{- if .Values.sidecars }} + {{- include "common.tplvalues.render" (dict "value" .Values.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + - name: common-scripts + configMap: + name: {{ printf "%s-common-scripts" (include "mongodb.fullname" .) }} + defaultMode: 0550 + {{- if or .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + configMap: + name: {{ template "mongodb.initdbScriptsCM" . }} + {{- end }} + {{- if or .Values.configuration .Values.existingConfigmap }} + - name: config + configMap: + name: {{ include "mongodb.configmapName" . }} + {{- end }} + {{- if .Values.extraVolumes }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraVolumes "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: certs + emptyDir: {} + {{- if (include "mongodb.autoGenerateCerts" .) }} + - name: certs-volume + secret: + secretName: {{ template "mongodb.tlsSecretName" . }} + items: + - key: mongodb-ca-cert + path: mongodb-ca-cert + mode: 0600 + - key: mongodb-ca-key + path: mongodb-ca-key + mode: 0600 + {{- else }} + - name: mongodb-certs-0 + secret: + secretName: {{ include "common.tplvalues.render" ( dict "value" .Values.tls.standalone.existingSecret "context" $) }} + defaultMode: 256 + {{- end }} + {{- end }} + {{- if not .Values.persistence.enabled }} + - name: datadir + {{- if .Values.persistence.medium }} + emptyDir: + medium: {{ .Values.persistence.medium | quote }} + {{- else }} + emptyDir: {} + {{- end }} + {{- else if .Values.persistence.existingClaim }} + - name: datadir + persistentVolumeClaim: + claimName: {{ printf "%s" (tpl .Values.persistence.existingClaim .) }} + {{- else if not .Values.useStatefulSet }} + - name: datadir + persistentVolumeClaim: + claimName: {{ template "mongodb.fullname" . }} + {{- else }} + volumeClaimTemplates: + - metadata: + name: datadir + {{- if .Values.persistence.annotations }} + annotations: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.annotations "context" $) | nindent 10 }} + {{- end }} + spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{- if .Values.persistence.volumeClaimTemplates.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.volumeClaimTemplates.selector "context" $) | nindent 10 }} + {{- end }} + {{ include "common.storage.class" (dict "persistence" .Values.persistence "global" .Values.global) }} + {{- end }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/standalone/pvc.yaml b/deployment/charts/mongodb/templates/standalone/pvc.yaml new file mode 100644 index 0000000..7786de6 --- /dev/null +++ b/deployment/charts/mongodb/templates/standalone/pvc.yaml @@ -0,0 +1,33 @@ +{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) (not (eq .Values.architecture "replicaset")) (not .Values.useStatefulSet) }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ include "mongodb.fullname" . }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: mongodb + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if or .Values.persistence.annotations .Values.commonAnnotations .Values.persistence.resourcePolicy }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.persistence.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.persistence.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.persistence.resourcePolicy }} + helm.sh/resource-policy: {{ .Values.persistence.resourcePolicy | quote }} + {{- end }} + {{- end }} +spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{ include "common.storage.class" (dict "persistence" .Values.persistence "global" .Values.global) }} +{{- end }} diff --git a/deployment/charts/mongodb/templates/standalone/svc.yaml b/deployment/charts/mongodb/templates/standalone/svc.yaml new file mode 100644 index 0000000..3abf07c --- /dev/null +++ b/deployment/charts/mongodb/templates/standalone/svc.yaml @@ -0,0 +1,61 @@ +{{- if not (eq .Values.architecture "replicaset") }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "mongodb.fullname" . }} + namespace: {{ include "mongodb.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: mongodb + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if or .Values.service.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.service.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.service.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: {{ .Values.service.type }} + {{- if and (eq .Values.service.type "ClusterIP") .Values.service.clusterIP }} + clusterIP: {{ .Values.service.clusterIP }} + {{- end }} + {{- if and (eq .Values.service.type "LoadBalancer") .Values.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + {{- if and (eq .Values.service.type "LoadBalancer") .Values.service.loadBalancerClass }} + loadBalancerClass: {{ .Values.service.loadBalancerClass }} + {{- end }} + {{- if .Values.service.externalIPs }} + externalIPs: {{ toYaml .Values.service.externalIPs | nindent 4 }} + {{- end }} + {{- if .Values.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: {{- toYaml .Values.service.loadBalancerSourceRanges | nindent 4 }} + {{- end }} + {{- if .Values.service.sessionAffinity }} + sessionAffinity: {{ .Values.service.sessionAffinity }} + {{- end }} + {{- if .Values.service.sessionAffinityConfig }} + sessionAffinityConfig: {{- include "common.tplvalues.render" (dict "value" .Values.service.sessionAffinityConfig "context" $) | nindent 4 }} + {{- end }} + {{- if (or (eq .Values.service.type "LoadBalancer") (eq .Values.service.type "NodePort")) }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy | quote }} + {{- end }} + ports: + - name: {{ .Values.service.portName | quote }} + port: {{ .Values.service.ports.mongodb }} + targetPort: mongodb + {{- if and (or (eq .Values.service.type "LoadBalancer") (eq .Values.service.type "NodePort")) .Values.service.nodePorts.mongodb }} + nodePort: {{ .Values.service.nodePorts.mongodb }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + {{- if .Values.service.extraPorts }} + {{- include "common.tplvalues.render" (dict "value" .Values.service.extraPorts "context" $) | nindent 4 }} + {{- end }} + selector: {{- include "common.labels.matchLabels" . | nindent 4 }} + app.kubernetes.io/component: mongodb +{{- end }} diff --git a/deployment/charts/mongodb/values.schema.json b/deployment/charts/mongodb/values.schema.json new file mode 100644 index 0000000..be8e54b --- /dev/null +++ b/deployment/charts/mongodb/values.schema.json @@ -0,0 +1,173 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "architecture": { + "type": "string", + "title": "MongoDB® architecture", + "form": true, + "description": "Allowed values: `standalone` or `replicaset`" + }, + "auth": { + "type": "object", + "title": "Authentication configuration", + "form": true, + "properties": { + "enabled": { + "type": "boolean", + "title": "Enable Authentication", + "form": true + }, + "rootUser": { + "type": "string", + "title": "MongoDB® admin user", + "form": true, + "description": "Name of the admin user. Default is root" + }, + "rootPassword": { + "type": "string", + "title": "MongoDB® admin password", + "form": true, + "description": "Defaults to a random 10-character alphanumeric string if not set", + "hidden": { + "value": false, + "path": "auth/enabled" + } + }, + "database": { + "type": "string", + "title": "MongoDB® custom database", + "description": "Name of the custom database to be created during the 1st initialization of MongoDB®", + "form": true + }, + "username": { + "type": "string", + "title": "MongoDB® custom user", + "description": "Name of the custom user to be created during the 1st initialization of MongoDB®. This user only has permissions on the MongoDB® custom database", + "form": true + }, + "password": { + "type": "string", + "title": "Password for MongoDB® custom user", + "form": true, + "description": "Defaults to a random 10-character alphanumeric string if not set", + "hidden": { + "value": false, + "path": "auth/enabled" + } + }, + "replicaSetKey": { + "type": "string", + "title": "Key used for replica set authentication", + "form": true, + "description": "Defaults to a random 10-character alphanumeric string if not set", + "hidden": { + "value": "standalone", + "path": "architecture" + } + } + } + }, + "replicaCount": { + "type": "integer", + "form": true, + "title": "Number of MongoDB® replicas", + "hidden": { + "value": "standalone", + "path": "architecture" + } + }, + "configuration": { + "type": "string", + "title": "MongoDB® Custom Configuration", + "form": true, + "render": "textArea" + }, + "arbiter": { + "type": "object", + "title": "Arbiter configuration", + "form": true, + "properties": { + "configuration": { + "type": "string", + "title": "Arbiter Custom Configuration", + "form": true, + "render": "textArea", + "hidden": { + "value": "standalone", + "path": "architecture" + } + } + } + }, + "persistence": { + "type": "object", + "title": "Persistence configuration", + "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", + "hidden": { + "value": false, + "path": "persistence/enabled" + }, + "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/deployment/charts/mongodb/values.yaml b/deployment/charts/mongodb/values.yaml new file mode 100644 index 0000000..6a424d8 --- /dev/null +++ b/deployment/charts/mongodb/values.yaml @@ -0,0 +1,2077 @@ +## @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 StorageClass for Persistent Volume(s) +## @param global.namespaceOverride Override the namespace for resource deployed by the chart, but can itself be overridden by the local namespaceOverride +## +global: + imageRegistry: "" + ## E.g. + ## imagePullSecrets: + ## - myRegistryKeySecretName + ## + imagePullSecrets: [] + storageClass: "" + namespaceOverride: "" + +## @section Common parameters +## + +## @param nameOverride String to partially override mongodb.fullname template (will maintain the release name) +## +nameOverride: "" +## @param fullnameOverride String to fully override mongodb.fullname template +## +fullnameOverride: "" +## @param namespaceOverride String to fully override common.names.namespace +## +namespaceOverride: "" +## @param kubeVersion Force target Kubernetes version (using Helm capabilities if not set) +## +kubeVersion: "" +## @param clusterDomain Default Kubernetes cluster domain +## +clusterDomain: cluster.local +## @param extraDeploy Array of extra objects to deploy with the release +## extraDeploy: +## This needs to be uncommented and added to 'extraDeploy' in order to use the replicaset 'mongo-labeler' sidecar +## for dynamically discovering the mongodb primary pod +## suggestion is to use a hard-coded and predictable TCP port for the primary mongodb pod (here is 30001, choose your own) +## - apiVersion: v1 +## kind: Service +## metadata: +## name: mongodb-primary +## namespace: the-mongodb-namespace +## labels: +## app.kubernetes.io/component: mongodb +## app.kubernetes.io/instance: mongodb +## app.kubernetes.io/managed-by: Helm +## app.kubernetes.io/name: mongodb +## spec: +## type: NodePort +## externalTrafficPolicy: Cluster +## ports: +## - name: mongodb +## port: 30001 +## nodePort: 30001 +## protocol: TCP +## targetPort: mongodb +## selector: +## app.kubernetes.io/component: mongodb +## app.kubernetes.io/instance: mongodb +## app.kubernetes.io/name: mongodb +## primary: "true" +## +extraDeploy: [] +## @param commonLabels Add labels to all the deployed resources (sub-charts are not considered). Evaluated as a template +## +commonLabels: {} +## @param commonAnnotations Common annotations to add to all Mongo resources (sub-charts are not considered). Evaluated as a template +## +commonAnnotations: {} + +## @param topologyKey Override common lib default topology key. If empty - "kubernetes.io/hostname" is used +## i.e. topologyKey: topology.kubernetes.io/zone +## +topologyKey: "" + +## 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 MongoDB(®) parameters +## + +## Bitnami MongoDB(®) image +## ref: https://hub.docker.com/r/bitnami/mongodb/tags/ +## @param image.registry MongoDB(®) image registry +## @param image.repository MongoDB(®) image registry +## @param image.tag MongoDB(®) image tag (immutable tags are recommended) +## @param image.digest MongoDB(®) image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag +## @param image.pullPolicy MongoDB(®) image pull policy +## @param image.pullSecrets Specify docker-registry secret names as an array +## @param image.debug Set to true if you would like to see extra information on logs +## +image: + registry: docker.io + repository: bitnami/mongodb + tag: 6.0.3-debian-11-r9 + digest: "" + ## Specify a imagePullPolicy + ## 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/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## Set to true if you would like to see extra information on logs + ## + debug: false + +## @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 architecture MongoDB(®) architecture (`standalone` or `replicaset`) +## +architecture: standalone +## @param useStatefulSet Set to true to use a StatefulSet instead of a Deployment (only when `architecture=standalone`) +## +useStatefulSet: false +## MongoDB(®) Authentication parameters +## +auth: + ## @param auth.enabled Enable authentication + ## ref: https://docs.mongodb.com/manual/tutorial/enable-authentication/ + ## + enabled: true + ## @param auth.rootUser MongoDB(®) root user + ## + rootUser: root + ## @param auth.rootPassword MongoDB(®) root password + ## ref: https://github.com/bitnami/containers/tree/main/bitnami/mongodb#setting-the-root-user-and-password-on-first-run + ## + rootPassword: "" + ## MongoDB(®) custom users and databases + ## ref: https://github.com/bitnami/containers/tree/main/bitnami/mongodb#creating-a-user-and-database-on-first-run + ## @param auth.usernames List of custom users to be created during the initialization + ## @param auth.passwords List of passwords for the custom users set at `auth.usernames` + ## @param auth.databases List of custom databases to be created during the initialization + ## + usernames: [] + passwords: [] + databases: [] + ## @param auth.username DEPRECATED: use `auth.usernames` instead + ## @param auth.password DEPRECATED: use `auth.passwords` instead + ## @param auth.database DEPRECATED: use `auth.databases` instead + username: "" + password: "" + database: "" + ## @param auth.replicaSetKey Key used for authentication in the replicaset (only when `architecture=replicaset`) + ## + replicaSetKey: "" + ## @param auth.existingSecret Existing secret with MongoDB(®) credentials (keys: `mongodb-passwords`, `mongodb-root-password`, `mongodb-metrics-password`, ` mongodb-replica-set-key`) + ## NOTE: When it's set the previous parameters are ignored. + ## + existingSecret: "" +tls: + ## @param tls.enabled Enable MongoDB(®) TLS support between nodes in the cluster as well as between mongo clients and nodes + ## + enabled: false + ## @param tls.autoGenerated Generate a custom CA and self-signed certificates + ## + autoGenerated: true + ## @param tls.existingSecret Existing secret with TLS certificates (keys: `mongodb-ca-cert`, `mongodb-ca-key`) + ## NOTE: When it's set it will disable secret creation. + ## + existingSecret: "" + ## Add Custom CA certificate + ## @param tls.caCert Custom CA certificated (base64 encoded) + ## @param tls.caKey CA certificate private key (base64 encoded) + ## + caCert: "" + caKey: "" + standalone: + ## @param tls.standalone.existingSecret Existing secret with TLS certificates (`tls.key`, `tls.crt`, `ca.crt`). + ## NOTE: When it's set it will disable certificate self-generation from existing CA. + ## + existingSecret: "" + replicaset: + ## @param tls.replicaset.existingSecrets Array of existing secrets with TLS certificates (`tls.key`, `tls.crt`, `ca.crt`). + ## existingSecrets: + ## - "mySecret-0" + ## - "mySecret-1" + ## NOTE: When it's set it will disable certificate self-generation from existing CA. + ## + existingSecrets: [] + hidden: + ## @param tls.hidden.existingSecrets Array of existing secrets with TLS certificates (`tls.key`, `tls.crt`, `ca.crt`). + ## existingSecrets: + ## - "mySecret-0" + ## - "mySecret-1" + ## NOTE: When it's set it will disable certificate self-generation from existing CA. + ## + existingSecrets: [] + arbiter: + ## @param tls.arbiter.existingSecret Existing secret with TLS certificates (`tls.key`, `tls.crt`, `ca.crt`). + ## NOTE: When it's set it will disable certificate self-generation from existing CA. + ## + existingSecret: "" + ## Bitnami Nginx image + ## @param tls.image.registry Init container TLS certs setup image registry + ## @param tls.image.repository Init container TLS certs setup image repository + ## @param tls.image.tag Init container TLS certs setup image tag (immutable tags are recommended) + ## @param tls.image.digest Init container TLS certs setup image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag + ## @param tls.image.pullPolicy Init container TLS certs setup image pull policy + ## @param tls.image.pullSecrets Init container TLS certs specify docker-registry secret names as an array + ## @param tls.extraDnsNames Add extra dns names to the CA, can solve x509 auth issue for pod clients + ## + image: + registry: docker.io + repository: bitnami/nginx + tag: 1.23.2-debian-11-r18 + 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/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + + ## e.g: + ## extraDnsNames + ## "DNS.6": "$my_host" + ## "DNS.7": "$test" + ## + extraDnsNames: [] + ## @param tls.mode Allows to set the tls mode which should be used when tls is enabled (options: `allowTLS`, `preferTLS`, `requireTLS`) + ## + mode: requireTLS + ## Init Container 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 tls.resources.limits Init container generate-tls-certs resource limits + ## @param tls.resources.requests Init container generate-tls-certs resource requests + ## + resources: + ## Example: + ## limits: + ## cpu: 100m + ## memory: 128Mi + ## + limits: {} + ## Examples: + ## requests: + ## cpu: 100m + ## memory: 128Mi + ## + requests: {} +## @param hostAliases Add deployment host aliases +## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ +## +hostAliases: [] +## @param replicaSetName Name of the replica set (only when `architecture=replicaset`) +## Ignored when mongodb.architecture=standalone +## +replicaSetName: rs0 +## @param replicaSetHostnames Enable DNS hostnames in the replicaset config (only when `architecture=replicaset`) +## Ignored when mongodb.architecture=standalone +## Ignored when externalAccess.enabled=true +## +replicaSetHostnames: true +## @param enableIPv6 Switch to enable/disable IPv6 on MongoDB(®) +## ref: https://github.com/bitnami/containers/tree/main/bitnami/mongodb#enablingdisabling-ipv6 +## +enableIPv6: false +## @param directoryPerDB Switch to enable/disable DirectoryPerDB on MongoDB(®) +## ref: https://github.com/bitnami/containers/tree/main/bitnami/mongodb#enablingdisabling-directoryperdb +## +directoryPerDB: false +## MongoDB(®) System Log configuration +## ref: https://github.com/bitnami/containers/tree/main/bitnami/mongodb#configuring-system-log-verbosity-level +## @param systemLogVerbosity MongoDB(®) system log verbosity level +## @param disableSystemLog Switch to enable/disable MongoDB(®) system log +## +systemLogVerbosity: 0 +disableSystemLog: false +## @param disableJavascript Switch to enable/disable MongoDB(®) server-side JavaScript execution +## ref: https://docs.mongodb.com/manual/core/server-side-javascript/ +## +disableJavascript: false +## @param enableJournal Switch to enable/disable MongoDB(®) Journaling +## ref: https://docs.mongodb.com/manual/reference/configuration-options/#mongodb-setting-storage.journal.enabled +## +enableJournal: true +## @param configuration MongoDB(®) configuration file to be used for Primary and Secondary nodes +## For documentation of all options, see: http://docs.mongodb.org/manual/reference/configuration-options/ +## Example: +## configuration: |- +## # where and how to store data. +## storage: +## dbPath: /bitnami/mongodb/data/db +## journal: +## enabled: true +## directoryPerDB: false +## # where to write logging data +## systemLog: +## destination: file +## quiet: false +## logAppend: true +## logRotate: reopen +## path: /opt/bitnami/mongodb/logs/mongodb.log +## verbosity: 0 +## # network interfaces +## net: +## port: 27017 +## unixDomainSocket: +## enabled: true +## pathPrefix: /opt/bitnami/mongodb/tmp +## ipv6: false +## bindIpAll: true +## # replica set options +## #replication: +## #replSetName: replicaset +## #enableMajorityReadConcern: true +## # process management options +## processManagement: +## fork: false +## pidFilePath: /opt/bitnami/mongodb/tmp/mongodb.pid +## # set parameter options +## setParameter: +## enableLocalhostAuthBypass: true +## # security options +## security: +## authorization: disabled +## #keyFile: /opt/bitnami/mongodb/conf/keyfile +## +configuration: "" +## @section replicaSetConfigurationSettings settings applied during runtime (not via configuration file) +## If enabled, these are applied by a script which is called within setup.sh +## for documentation see https://docs.mongodb.com/manual/reference/replica-configuration/#replica-set-configuration-fields +## @param replicaSetConfigurationSettings.enabled Enable MongoDB(®) Switch to enable/disable configuring MongoDB(®) run time rs.conf settings +## @param replicaSetConfigurationSettings.configuration run-time rs.conf settings +## +replicaSetConfigurationSettings: + enabled: false + configuration: {} +## chainingAllowed : false +## heartbeatTimeoutSecs : 10 +## heartbeatIntervalMillis : 2000 +## electionTimeoutMillis : 10000 +## catchUpTimeoutMillis : 30000 +## @param existingConfigmap Name of existing ConfigMap with MongoDB(®) configuration for Primary and Secondary nodes +## NOTE: When it's set the arbiter.configuration parameter is ignored +## +existingConfigmap: "" +## @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 Existing ConfigMap with custom initdb scripts +## +initdbScriptsConfigMap: "" +## Command and args for running the container (set to default if not set). Use array form +## @param command Override default container command (useful when using custom images) +## @param args Override default container args (useful when using custom images) +## +command: [] +args: [] +## @param extraFlags MongoDB(®) additional command line flags +## Example: +## extraFlags: +## - "--wiredTigerCacheSizeGB=2" +## +extraFlags: [] +## @param extraEnvVars Extra environment variables to add to MongoDB(®) pods +## E.g: +## extraEnvVars: +## - name: FOO +## value: BAR +## +extraEnvVars: [] +## @param extraEnvVarsCM Name of existing ConfigMap containing extra env vars +## +extraEnvVarsCM: "" +## @param extraEnvVarsSecret Name of existing Secret containing extra env vars (in case of sensitive data) +## +extraEnvVarsSecret: "" + +## @section MongoDB(®) statefulset parameters +## + +## @param annotations Additional labels to be added to the MongoDB(®) statefulset. Evaluated as a template +## +annotations: {} +## @param labels Annotations to be added to the MongoDB(®) statefulset. Evaluated as a template +## +labels: {} +## @param replicaCount Number of MongoDB(®) nodes (only when `architecture=replicaset`) +## Ignored when mongodb.architecture=standalone +## +replicaCount: 2 +## @param updateStrategy.type Strategy to use to replace existing MongoDB(®) pods. When architecture=standalone and useStatefulSet=false, +## this parameter will be applied on a deployment object. In other case it will be applied on a statefulset object +## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies +## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy +## Example: +## updateStrategy: +## type: RollingUpdate +## rollingUpdate: +## maxSurge: 25% +## maxUnavailable: 25% +## +updateStrategy: + type: RollingUpdate +## @param podManagementPolicy Pod management policy for MongoDB(®) +## Should be initialized one by one when building the replicaset for the first time +## +podManagementPolicy: OrderedReady +## @param podAffinityPreset MongoDB(®) Pod affinity preset. Ignored if `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 podAntiAffinityPreset MongoDB(®) Pod anti-affinity preset. Ignored if `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 +## Node affinity preset +## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity +## +nodeAffinityPreset: + ## @param nodeAffinityPreset.type MongoDB(®) Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` + ## + type: "" + ## @param nodeAffinityPreset.key MongoDB(®) Node label key to match Ignored if `affinity` is set. + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## @param nodeAffinityPreset.values MongoDB(®) Node label values to match. Ignored if `affinity` is set. + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] +## @param affinity MongoDB(®) Affinity for pod 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 nodeSelector MongoDB(®) Node labels for pod assignment +## ref: https://kubernetes.io/docs/user-guide/node-selection/ +## +nodeSelector: {} +## @param tolerations MongoDB(®) Tolerations for pod assignment +## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ +## +tolerations: [] +## @param topologySpreadConstraints MongoDB(®) Spread Constraints for Pods +## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ +## +topologySpreadConstraints: [] +## @param lifecycleHooks LifecycleHook for the MongoDB(®) container(s) to automate configuration before or after startup +## +lifecycleHooks: {} +## @param terminationGracePeriodSeconds MongoDB(®) Termination Grace Period +## +terminationGracePeriodSeconds: "" +## @param podLabels MongoDB(®) pod labels +## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ +## +podLabels: {} +## @param podAnnotations MongoDB(®) Pod annotations +## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ +## +podAnnotations: {} +## @param priorityClassName Name of the existing priority class to be used by MongoDB(®) pod(s) +## ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ +## +priorityClassName: "" +## @param runtimeClassName Name of the runtime class to be used by MongoDB(®) pod(s) +## ref: https://kubernetes.io/docs/concepts/containers/runtime-class/ +## +runtimeClassName: "" +## MongoDB(®) pods' Security Context. +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod +## @param podSecurityContext.enabled Enable MongoDB(®) pod(s)' Security Context +## @param podSecurityContext.fsGroup Group ID for the volumes of the MongoDB(®) pod(s) +## @param podSecurityContext.sysctls sysctl settings of the MongoDB(®) pod(s)' +## +podSecurityContext: + enabled: true + fsGroup: 1001 + ## sysctl settings + ## Example: + ## sysctls: + ## - name: net.core.somaxconn + ## value: "10000" + ## + sysctls: [] +## MongoDB(®) containers' Security Context (main and metrics container). +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container +## @param containerSecurityContext.enabled Enable MongoDB(®) container(s)' Security Context +## @param containerSecurityContext.runAsUser User ID for the MongoDB(®) container +## @param containerSecurityContext.runAsNonRoot Set MongoDB(®) container's Security Context runAsNonRoot +## +containerSecurityContext: + enabled: true + runAsUser: 1001 + runAsNonRoot: true +## MongoDB(®) containers' 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 resources.limits The resources limits for MongoDB(®) containers +## @param resources.requests The requested resources for MongoDB(®) containers +## +resources: + ## Example: + ## limits: + ## cpu: 100m + ## memory: 128Mi + ## + limits: {} + ## Examples: + ## requests: + ## cpu: 100m + ## memory: 128Mi + ## + requests: {} +## @param containerPorts.mongodb MongoDB(®) container port +containerPorts: + mongodb: 27017 +## MongoDB(®) pods' liveness probe. Evaluated as a template. +## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes +## @param livenessProbe.enabled Enable livenessProbe +## @param livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe +## @param livenessProbe.periodSeconds Period seconds for livenessProbe +## @param livenessProbe.timeoutSeconds Timeout seconds for livenessProbe +## @param livenessProbe.failureThreshold Failure threshold for livenessProbe +## @param livenessProbe.successThreshold Success threshold for livenessProbe +## +livenessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 20 + timeoutSeconds: 10 + failureThreshold: 6 + successThreshold: 1 +## MongoDB(®) pods' readiness probe. Evaluated as a template. +## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes +## @param readinessProbe.enabled Enable readinessProbe +## @param readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe +## @param readinessProbe.periodSeconds Period seconds for readinessProbe +## @param readinessProbe.timeoutSeconds Timeout seconds for readinessProbe +## @param readinessProbe.failureThreshold Failure threshold for readinessProbe +## @param readinessProbe.successThreshold Success threshold for readinessProbe +## +readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 +## Slow starting containers can be protected through startup probes +## Startup probes are available in Kubernetes version 1.16 and above +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-startup-probes +## @param startupProbe.enabled Enable startupProbe +## @param startupProbe.initialDelaySeconds Initial delay seconds for startupProbe +## @param startupProbe.periodSeconds Period seconds for startupProbe +## @param startupProbe.timeoutSeconds Timeout seconds for startupProbe +## @param startupProbe.failureThreshold Failure threshold for startupProbe +## @param startupProbe.successThreshold Success threshold for startupProbe +## +startupProbe: + enabled: false + initialDelaySeconds: 5 + periodSeconds: 20 + timeoutSeconds: 10 + successThreshold: 1 + failureThreshold: 30 +## @param customLivenessProbe Override default liveness probe for MongoDB(®) containers +## Ignored when livenessProbe.enabled=true +## +customLivenessProbe: {} +## @param customReadinessProbe Override default readiness probe for MongoDB(®) containers +## Ignored when readinessProbe.enabled=true +## +customReadinessProbe: {} +## @param customStartupProbe Override default startup probe for MongoDB(®) containers +## Ignored when startupProbe.enabled=true +## +customStartupProbe: {} +## @param initContainers Add additional init containers for the hidden node pod(s) +## Example: +## initContainers: +## - name: your-image-name +## image: your-image +## imagePullPolicy: Always +## ports: +## - name: portname +## containerPort: 1234 +## +initContainers: [] +## @param sidecars Add additional sidecar containers for the MongoDB(®) pod(s) +## Example: +## sidecars: +## - name: your-image-name +## image: your-image +## imagePullPolicy: Always +## ports: +## - name: portname +## containerPort: 1234 +## This is an optional 'mongo-labeler' sidecar container that tracks replica-set for the primary mongodb pod +## and labels it dynamically with ' primary: "true" ' in order for an extra-deployed service to always expose +## and attach to the primary pod, this needs to be uncommented along with the suggested 'extraDeploy' example +## and the suggested rbac example for the pod to be allowed adding labels to mongo replica pods +## search 'mongo-labeler' through this file to find the sections that needs to be uncommented to make it work +## +## - name: mongo-labeler +## image: korenlev/k8s-mongo-labeler-sidecar +## imagePullPolicy: Always +## env: +## - name: LABEL_SELECTOR +## value: "app.kubernetes.io/component=mongodb,app.kubernetes.io/instance=mongodb,app.kubernetes.io/name=mongodb" +## - name: NAMESPACE +## value: "the-mongodb-namespace" +## - name: DEBUG +## value: "true" +## +sidecars: [] +## @param extraVolumeMounts Optionally specify extra list of additional volumeMounts for the MongoDB(®) container(s) +## Examples: +## extraVolumeMounts: +## - name: extras +## mountPath: /usr/share/extras +## readOnly: true +## +extraVolumeMounts: [] +## @param extraVolumes Optionally specify extra list of additional volumes to the MongoDB(®) statefulset +## extraVolumes: +## - name: extras +## emptyDir: {} +## +extraVolumes: [] +## MongoDB(®) Pod Disruption Budget configuration +## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/ +## +pdb: + ## @param pdb.create Enable/disable a Pod Disruption Budget creation for MongoDB(®) pod(s) + ## + create: false + ## @param pdb.minAvailable Minimum number/percentage of MongoDB(®) pods that must still be available after the eviction + ## + minAvailable: 1 + ## @param pdb.maxUnavailable Maximum number/percentage of MongoDB(®) pods that may be made unavailable after the eviction + ## + maxUnavailable: "" + +## @section Traffic exposure parameters +## + +## Service parameters +## +service: + ## @param service.nameOverride MongoDB(®) service name + ## + nameOverride: "" + ## @param service.type Kubernetes Service type (only for standalone architecture) + ## + type: ClusterIP + ## @param service.portName MongoDB(®) service port name (only for standalone architecture) + ## + portName: mongodb + ## @param service.ports.mongodb MongoDB(®) service port. + ## + ports: + mongodb: 27017 + ## @param service.nodePorts.mongodb Port to bind to for NodePort and LoadBalancer service types (only for standalone architecture) + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## + nodePorts: + mongodb: "" + ## @param service.clusterIP MongoDB(®) service cluster IP (only for standalone architecture) + ## e.g: + ## clusterIP: None + ## + clusterIP: "" + ## @param service.externalIPs Specify the externalIP value ClusterIP service type (only for standalone architecture) + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#external-ips + ## + externalIPs: [] + ## @param service.loadBalancerIP loadBalancerIP for MongoDB(®) Service (only for standalone architecture) + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer + ## + loadBalancerIP: "" + ## @param service.loadBalancerClass loadBalancerClass for MongoDB(®) Service (only for standalone architecture) + # ref: https://kubernetes.io/docs/concepts/services-networking/service/#load-balancer-class + loadBalancerClass: "" + ## @param service.loadBalancerSourceRanges Address(es) that are allowed when service is LoadBalancer (only for standalone architecture) + ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## + loadBalancerSourceRanges: [] + ## @param service.extraPorts Extra ports to expose (normally used with the `sidecar` value) + ## + extraPorts: [] + ## @param service.annotations Provide any additional annotations that may be required + ## + annotations: {} + ## @param service.externalTrafficPolicy service external traffic policy (only for standalone architecture) + ## ref https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + ## + externalTrafficPolicy: Local + ## @param service.sessionAffinity Control where client requests go, to the same pod or round-robin + ## Values: ClientIP or None + ## ref: https://kubernetes.io/docs/user-guide/services/ + ## + sessionAffinity: None + ## @param service.sessionAffinityConfig Additional settings for the sessionAffinity + ## sessionAffinityConfig: + ## clientIP: + ## timeoutSeconds: 300 + ## + sessionAffinityConfig: {} +## External Access to MongoDB(®) nodes configuration +## +externalAccess: + ## @param externalAccess.enabled Enable Kubernetes external cluster access to MongoDB(®) nodes (only for replicaset architecture) + ## + enabled: false + ## External IPs auto-discovery configuration + ## An init container is used to auto-detect LB IPs or node ports by querying the K8s API + ## Note: RBAC might be required + ## + autoDiscovery: + ## @param externalAccess.autoDiscovery.enabled Enable using an init container to auto-detect external IPs by querying the K8s API + ## + enabled: false + ## Bitnami Kubectl image + ## ref: https://hub.docker.com/r/bitnami/kubectl/tags/ + ## @param externalAccess.autoDiscovery.image.registry Init container auto-discovery image registry + ## @param externalAccess.autoDiscovery.image.repository Init container auto-discovery image repository + ## @param externalAccess.autoDiscovery.image.tag Init container auto-discovery image tag (immutable tags are recommended) + ## @param externalAccess.autoDiscovery.image.digest Init container auto-discovery image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag + ## @param externalAccess.autoDiscovery.image.pullPolicy Init container auto-discovery image pull policy + ## @param externalAccess.autoDiscovery.image.pullSecrets Init container auto-discovery image pull secrets + ## + image: + registry: docker.io + repository: bitnami/kubectl + tag: 1.25.5-debian-11-r0 + 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: [] + ## Init Container 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 externalAccess.autoDiscovery.resources.limits Init container auto-discovery resource limits + ## @param externalAccess.autoDiscovery.resources.requests Init container auto-discovery resource requests + ## + resources: + ## Example: + ## limits: + ## cpu: 100m + ## memory: 128Mi + ## + limits: {} + ## Examples: + ## requests: + ## cpu: 100m + ## memory: 128Mi + ## + requests: {} + ## Parameters to configure K8s service(s) used to externally access MongoDB(®) + ## A new service per broker will be created + ## + service: + ## @param externalAccess.service.type Kubernetes Service type for external access. Allowed values: NodePort, LoadBalancer or ClusterIP + ## + type: LoadBalancer + ## @param externalAccess.service.portName MongoDB(®) port name used for external access when service type is LoadBalancer + ## + portName: "mongodb" + ## @param externalAccess.service.ports.mongodb MongoDB(®) port used for external access when service type is LoadBalancer + ## + ports: + mongodb: 27017 + ## @param externalAccess.service.loadBalancerIPs Array of load balancer IPs for MongoDB(®) nodes + ## Example: + ## loadBalancerIPs: + ## - X.X.X.X + ## - Y.Y.Y.Y + ## + loadBalancerIPs: [] + ## @param externalAccess.service.loadBalancerClass loadBalancerClass when service type is LoadBalancer + # ref: https://kubernetes.io/docs/concepts/services-networking/service/#load-balancer-class + loadBalancerClass: "" + ## @param externalAccess.service.loadBalancerSourceRanges Address(es) that are allowed when service is LoadBalancer + ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## Example: + ## loadBalancerSourceRanges: + ## - 10.10.10.0/24 + ## + loadBalancerSourceRanges: [] + ## @param externalAccess.service.externalTrafficPolicy MongoDB(®) service external traffic policy + ## ref https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + ## + externalTrafficPolicy: Local + ## @param externalAccess.service.nodePorts Array of node ports used to configure MongoDB(®) advertised hostname when service type is NodePort + ## Example: + ## nodePorts: + ## - 30001 + ## - 30002 + ## + nodePorts: [] + ## @param externalAccess.service.domain Domain or external IP used to configure MongoDB(®) advertised hostname when service type is NodePort + ## If not specified, the container will try to get the kubernetes node external IP + ## e.g: + ## domain: mydomain.com + ## + domain: "" + ## @param externalAccess.service.extraPorts Extra ports to expose (normally used with the `sidecar` value) + ## + extraPorts: [] + ## @param externalAccess.service.annotations Service annotations for external access + ## + annotations: {} + ## @param externalAccess.service.sessionAffinity Control where client requests go, to the same pod or round-robin + ## Values: ClientIP or None + ## ref: https://kubernetes.io/docs/user-guide/services/ + ## + sessionAffinity: None + ## @param externalAccess.service.sessionAffinityConfig Additional settings for the sessionAffinity + ## sessionAffinityConfig: + ## clientIP: + ## timeoutSeconds: 300 + ## + sessionAffinityConfig: {} + ## External Access to MongoDB(®) Hidden nodes configuration + ## + hidden: + ## @param externalAccess.hidden.enabled Enable Kubernetes external cluster access to MongoDB(®) hidden nodes + ## + enabled: false + ## Parameters to configure K8s service(s) used to externally access MongoDB(®) + ## A new service per broker will be created + ## + service: + ## @param externalAccess.hidden.service.type Kubernetes Service type for external access. Allowed values: NodePort or LoadBalancer + ## + type: LoadBalancer + ## @param externalAccess.hidden.service.portName MongoDB(®) port name used for external access when service type is LoadBalancer + ## + portName: "mongodb" + ## @param externalAccess.hidden.service.ports.mongodb MongoDB(®) port used for external access when service type is LoadBalancer + ## + ports: + mongodb: 27017 + ## @param externalAccess.hidden.service.loadBalancerIPs Array of load balancer IPs for MongoDB(®) nodes + ## Example: + ## loadBalancerIPs: + ## - X.X.X.X + ## - Y.Y.Y.Y + ## + loadBalancerIPs: [] + ## @param externalAccess.hidden.service.loadBalancerClass loadBalancerClass when service type is LoadBalancer + # ref: https://kubernetes.io/docs/concepts/services-networking/service/#load-balancer-class + loadBalancerClass: "" + ## @param externalAccess.hidden.service.loadBalancerSourceRanges Address(es) that are allowed when service is LoadBalancer + ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## Example: + ## loadBalancerSourceRanges: + ## - 10.10.10.0/24 + ## + loadBalancerSourceRanges: [] + ## @param externalAccess.hidden.service.externalTrafficPolicy MongoDB(®) service external traffic policy + ## ref https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + ## + externalTrafficPolicy: Local + ## @param externalAccess.hidden.service.nodePorts Array of node ports used to configure MongoDB(®) advertised hostname when service type is NodePort. Length must be the same as replicaCount + ## Example: + ## nodePorts: + ## - 30001 + ## - 30002 + ## + nodePorts: [] + ## @param externalAccess.hidden.service.domain Domain or external IP used to configure MongoDB(®) advertised hostname when service type is NodePort + ## If not specified, the container will try to get the kubernetes node external IP + ## e.g: + ## domain: mydomain.com + ## + domain: "" + ## @param externalAccess.hidden.service.extraPorts Extra ports to expose (normally used with the `sidecar` value) + ## + extraPorts: [] + ## @param externalAccess.hidden.service.annotations Service annotations for external access + ## + annotations: {} + ## @param externalAccess.hidden.service.sessionAffinity Control where client requests go, to the same pod or round-robin + ## Values: ClientIP or None + ## ref: https://kubernetes.io/docs/user-guide/services/ + ## + sessionAffinity: None + ## @param externalAccess.hidden.service.sessionAffinityConfig Additional settings for the sessionAffinity + ## sessionAffinityConfig: + ## clientIP: + ## timeoutSeconds: 300 + ## + sessionAffinityConfig: {} + +## @section Persistence parameters +## + +## Enable persistence using Persistent Volume Claims +## ref: https://kubernetes.io/docs/user-guide/persistent-volumes/ +## +persistence: + ## @param persistence.enabled Enable MongoDB(®) data persistence using PVC + ## + enabled: true + ## @param persistence.medium Provide a medium for `emptyDir` volumes. + ## Requires persistence.enabled: false + ## + medium: "" + ## @param persistence.existingClaim Provide an existing `PersistentVolumeClaim` (only when `architecture=standalone`) + ## Requires persistence.enabled: true + ## If defined, PVC must be created manually before volume will be bound + ## Ignored when mongodb.architecture=replicaset + ## + existingClaim: "" + ## @param persistence.resourcePolicy Setting it to "keep" to avoid removing PVCs during a helm delete operation. Leaving it empty will delete PVCs after the chart deleted + resourcePolicy: "" + ## @param persistence.storageClass PVC Storage Class for MongoDB(®) data volume + ## 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. + ## + storageClass: "" + ## @param persistence.accessModes PV Access Mode + ## + accessModes: + - ReadWriteOnce + ## @param persistence.size PVC Storage Request for MongoDB(®) data volume + ## + size: 8Gi + ## @param persistence.annotations PVC annotations + ## + annotations: {} + ## @param persistence.mountPath Path to mount the volume at + ## MongoDB(®) images. + ## + mountPath: /bitnami/mongodb + ## @param persistence.subPath Subdirectory of the volume to mount at + ## and one PV for multiple services. + ## + subPath: "" + ## Fine tuning for volumeClaimTemplates + ## + volumeClaimTemplates: + ## @param persistence.volumeClaimTemplates.selector A label query over volumes to consider for binding (e.g. when using local volumes) + ## A label query over volumes to consider for binding (e.g. when using local volumes) + ## See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#labelselector-v1-meta for more details + ## + selector: {} + ## @param persistence.volumeClaimTemplates.requests Custom PVC requests attributes + ## Sometime cloud providers use additional requests attributes to provision custom storage instance + ## See https://cloud.ibm.com/docs/containers?topic=containers-file_storage#file_dynamic_statefulset + ## + requests: {} + ## @param persistence.volumeClaimTemplates.dataSource Add dataSource to the VolumeClaimTemplate + ## + dataSource: {} + +## @section RBAC parameters +## + +## ServiceAccount +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +## +serviceAccount: + ## @param serviceAccount.create Enable creation of ServiceAccount for MongoDB(®) pods + ## + create: true + ## @param serviceAccount.name Name of the created serviceAccount + ## If not set and create is true, a name is generated using the mongodb.fullname template + ## + name: "" + ## @param serviceAccount.annotations Additional Service Account annotations + ## + annotations: {} + ## @param serviceAccount.automountServiceAccountToken Allows auto mount of ServiceAccountToken on the serviceAccount created + ## Can be set to false if pods using this serviceAccount do not need to use K8s API + ## + automountServiceAccountToken: true +## Role Based Access +## ref: https://kubernetes.io/docs/admin/authorization/rbac/ +## +rbac: + ## @param rbac.create Whether to create & use RBAC resources or not + ## binding MongoDB(®) ServiceAccount to a role + ## that allows MongoDB(®) pods querying the K8s API + ## this needs to be set to 'true' to enable the mongo-labeler sidecar primary mongodb discovery + ## + create: false + ## @param rbac.rules Custom rules to create following the role specification + ## The example below needs to be uncommented to use the 'mongo-labeler' sidecar for dynamic discovery of the primary mongodb pod: + ## rules: + ## - apiGroups: + ## - "" + ## resources: + ## - pods + ## verbs: + ## - get + ## - list + ## - watch + ## - update + ## + rules: [] +## PodSecurityPolicy configuration +## Be sure to also set rbac.create to true, otherwise Role and RoleBinding won't be created. +## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/ +## +podSecurityPolicy: + ## @param podSecurityPolicy.create Whether to create a PodSecurityPolicy. WARNING: PodSecurityPolicy is deprecated in Kubernetes v1.21 or later, unavailable in v1.25 or later + ## + create: false + ## @param podSecurityPolicy.allowPrivilegeEscalation Enable privilege escalation + ## Either use predefined policy with some adjustments or use `podSecurityPolicy.spec` + ## + allowPrivilegeEscalation: false + ## @param podSecurityPolicy.privileged Allow privileged + ## + privileged: false + ## @param podSecurityPolicy.spec Specify the full spec to use for Pod Security Policy + ## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/ + ## Defining a spec ignores the above values. + ## + spec: {} + ## Example: + ## allowPrivilegeEscalation: false + ## fsGroup: + ## rule: 'MustRunAs' + ## ranges: + ## - min: 1001 + ## max: 1001 + ## hostIPC: false + ## hostNetwork: false + ## hostPID: false + ## privileged: false + ## readOnlyRootFilesystem: false + ## requiredDropCapabilities: + ## - ALL + ## runAsUser: + ## rule: 'MustRunAs' + ## ranges: + ## - min: 1001 + ## max: 1001 + ## seLinux: + ## rule: 'RunAsAny' + ## supplementalGroups: + ## rule: 'MustRunAs' + ## ranges: + ## - min: 1001 + ## max: 1001 + ## volumes: + ## - 'configMap' + ## - 'secret' + ## - 'emptyDir' + ## - 'persistentVolumeClaim' + ## + +## @section Volume Permissions parameters +## +## Init Container parameters +## Change the owner and group of the persistent volume(s) mountpoint(s) to 'runAsUser:fsGroup' on each component +## values from the securityContext section of the component +## +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: "" + ## 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: [] + ## Init Container 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 volumePermissions.resources.limits Init container volume-permissions resource limits + ## @param volumePermissions.resources.requests Init container volume-permissions resource requests + ## + resources: + ## Example: + ## limits: + ## cpu: 100m + ## memory: 128Mi + ## + limits: {} + ## Examples: + ## requests: + ## cpu: 100m + ## memory: 128Mi + ## + requests: {} + ## Init container Security Context + ## Note: the chown of the data folder is done to containerSecurityContext.runAsUser + ## and not the below volumePermissions.securityContext.runAsUser + ## When runAsUser is set to special value "auto", init container will try to chwon the + ## data folder to autodetermined user&group, using commands: `id -u`:`id -G | cut -d" " -f2` + ## "auto" is especially useful for OpenShift which has scc with dynamic userids (and 0 is not allowed). + ## You may want to use this volumePermissions.securityContext.runAsUser="auto" in combination with + ## podSecurityContext.enabled=false,containerSecurityContext.enabled=false and shmVolume.chmod.enabled=false + ## @param volumePermissions.securityContext.runAsUser User ID for the volumePermissions container + ## + securityContext: + runAsUser: 0 + +## @section Arbiter parameters +## + +arbiter: + ## @param arbiter.enabled Enable deploying the arbiter + ## https://docs.mongodb.com/manual/tutorial/add-replica-set-arbiter/ + ## + enabled: true + ## @param arbiter.hostAliases Add deployment host aliases + ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ + ## + hostAliases: [] + ## @param arbiter.configuration Arbiter configuration file to be used + ## http://docs.mongodb.org/manual/reference/configuration-options/ + ## + configuration: "" + ## @param arbiter.existingConfigmap Name of existing ConfigMap with Arbiter configuration + ## NOTE: When it's set the arbiter.configuration parameter is ignored + ## + existingConfigmap: "" + ## Command and args for running the container (set to default if not set). Use array form + ## @param arbiter.command Override default container command (useful when using custom images) + ## @param arbiter.args Override default container args (useful when using custom images) + ## + command: [] + args: [] + ## @param arbiter.extraFlags Arbiter additional command line flags + ## Example: + ## extraFlags: + ## - "--wiredTigerCacheSizeGB=2" + ## + extraFlags: [] + ## @param arbiter.extraEnvVars Extra environment variables to add to Arbiter pods + ## E.g: + ## extraEnvVars: + ## - name: FOO + ## value: BAR + ## + extraEnvVars: [] + ## @param arbiter.extraEnvVarsCM Name of existing ConfigMap containing extra env vars + ## + extraEnvVarsCM: "" + ## @param arbiter.extraEnvVarsSecret Name of existing Secret containing extra env vars (in case of sensitive data) + ## + extraEnvVarsSecret: "" + ## @param arbiter.annotations Additional labels to be added to the Arbiter statefulset + ## + annotations: {} + ## @param arbiter.labels Annotations to be added to the Arbiter statefulset + ## + labels: {} + ## @param arbiter.topologySpreadConstraints MongoDB(®) Spread Constraints for arbiter Pods + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ + ## + topologySpreadConstraints: [] + ## @param arbiter.lifecycleHooks LifecycleHook for the Arbiter container to automate configuration before or after startup + ## + lifecycleHooks: {} + ## @param arbiter.terminationGracePeriodSeconds Arbiter Termination Grace Period + ## + terminationGracePeriodSeconds: "" + ## @param arbiter.updateStrategy.type Strategy that will be employed to update Pods in the StatefulSet + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies + ## updateStrategy: + ## type: RollingUpdate + ## rollingUpdate: + ## maxSurge: 25% + ## maxUnavailable: 25% + ## + updateStrategy: + type: RollingUpdate + ## @param arbiter.podManagementPolicy Pod management policy for MongoDB(®) + ## Should be initialized one by one when building the replicaset for the first time + ## + podManagementPolicy: OrderedReady + ## @param arbiter.schedulerName Name of the scheduler (other than default) to dispatch pods + ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ + ## + schedulerName: "" + ## @param arbiter.podAffinityPreset Arbiter Pod affinity preset. Ignored if `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 arbiter.podAntiAffinityPreset Arbiter Pod anti-affinity preset. Ignored if `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 + ## Node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## + nodeAffinityPreset: + ## @param arbiter.nodeAffinityPreset.type Arbiter Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` + ## + type: "" + ## @param arbiter.nodeAffinityPreset.key Arbiter Node label key to match Ignored if `affinity` is set. + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## @param arbiter.nodeAffinityPreset.values Arbiter Node label values to match. Ignored if `affinity` is set. + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + ## @param arbiter.affinity Arbiter Affinity for pod assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## Note: arbiter.podAffinityPreset, arbiter.podAntiAffinityPreset, and arbiter.nodeAffinityPreset will be ignored when it's set + ## + affinity: {} + ## @param arbiter.nodeSelector Arbiter Node labels for pod assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + ## @param arbiter.tolerations Arbiter Tolerations for pod assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + ## @param arbiter.podLabels Arbiter pod labels + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + ## + podLabels: {} + ## @param arbiter.podAnnotations Arbiter Pod annotations + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + podAnnotations: {} + ## @param arbiter.priorityClassName Name of the existing priority class to be used by Arbiter pod(s) + ## ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ + ## + priorityClassName: "" + ## @param arbiter.runtimeClassName Name of the runtime class to be used by Arbiter pod(s) + ## ref: https://kubernetes.io/docs/concepts/containers/runtime-class/ + ## + runtimeClassName: "" + ## MongoDB(®) Arbiter pods' Security Context. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod + ## @param arbiter.podSecurityContext.enabled Enable Arbiter pod(s)' Security Context + ## @param arbiter.podSecurityContext.fsGroup Group ID for the volumes of the Arbiter pod(s) + ## @param arbiter.podSecurityContext.sysctls sysctl settings of the Arbiter pod(s)' + ## + podSecurityContext: + enabled: true + fsGroup: 1001 + ## sysctl settings + ## Example: + ## sysctls: + ## - name: net.core.somaxconn + ## value: "10000" + ## + sysctls: [] + ## MongoDB(®) Arbiter containers' Security Context (only main container). + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + ## @param arbiter.containerSecurityContext.enabled Enable Arbiter container(s)' Security Context + ## @param arbiter.containerSecurityContext.runAsUser User ID for the Arbiter container + ## @param arbiter.containerSecurityContext.runAsNonRoot Set Arbiter containers' Security Context runAsNonRoot + ## + containerSecurityContext: + enabled: true + runAsUser: 1001 + runAsNonRoot: true + ## MongoDB(®) Arbiter containers' 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 arbiter.resources.limits The resources limits for Arbiter containers + ## @param arbiter.resources.requests The requested resources for Arbiter containers + ## + resources: + ## Example: + ## limits: + ## cpu: 100m + ## memory: 128Mi + ## + limits: {} + ## Examples: + ## requests: + ## cpu: 100m + ## memory: 128Mi + ## + requests: {} + ## @param arbiter.containerPorts.mongodb MongoDB(®) arbiter container port + ## + containerPorts: + mongodb: 27017 + ## MongoDB(®) Arbiter pods' liveness probe. Evaluated as a template. + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes + ## @param arbiter.livenessProbe.enabled Enable livenessProbe + ## @param arbiter.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe + ## @param arbiter.livenessProbe.periodSeconds Period seconds for livenessProbe + ## @param arbiter.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe + ## @param arbiter.livenessProbe.failureThreshold Failure threshold for livenessProbe + ## @param arbiter.livenessProbe.successThreshold Success threshold for livenessProbe + ## + livenessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 20 + timeoutSeconds: 10 + failureThreshold: 6 + successThreshold: 1 + ## MongoDB(®) Arbiter pods' readiness probe. Evaluated as a template. + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes + ## @param arbiter.readinessProbe.enabled Enable readinessProbe + ## @param arbiter.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe + ## @param arbiter.readinessProbe.periodSeconds Period seconds for readinessProbe + ## @param arbiter.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe + ## @param arbiter.readinessProbe.failureThreshold Failure threshold for readinessProbe + ## @param arbiter.readinessProbe.successThreshold Success threshold for readinessProbe + ## + readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 20 + timeoutSeconds: 10 + failureThreshold: 6 + successThreshold: 1 + ## MongoDB(®) Arbiter pods' startup probe. Evaluated as a template. + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes + ## @param arbiter.startupProbe.enabled Enable startupProbe + ## @param arbiter.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe + ## @param arbiter.startupProbe.periodSeconds Period seconds for startupProbe + ## @param arbiter.startupProbe.timeoutSeconds Timeout seconds for startupProbe + ## @param arbiter.startupProbe.failureThreshold Failure threshold for startupProbe + ## @param arbiter.startupProbe.successThreshold Success threshold for startupProbe + ## + startupProbe: + enabled: false + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 30 + ## @param arbiter.customLivenessProbe Override default liveness probe for Arbiter containers + ## Ignored when arbiter.livenessProbe.enabled=true + ## + customLivenessProbe: {} + ## @param arbiter.customReadinessProbe Override default readiness probe for Arbiter containers + ## Ignored when arbiter.readinessProbe.enabled=true + ## + customReadinessProbe: {} + ## @param arbiter.customStartupProbe Override default startup probe for Arbiter containers + ## Ignored when arbiter.startupProbe.enabled=true + ## + customStartupProbe: {} + ## @param arbiter.initContainers Add additional init containers for the Arbiter pod(s) + ## Example: + ## initContainers: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + initContainers: [] + ## @param arbiter.sidecars Add additional sidecar containers for the Arbiter pod(s) + ## Example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + ## @param arbiter.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the Arbiter container(s) + ## Examples: + ## extraVolumeMounts: + ## - name: extras + ## mountPath: /usr/share/extras + ## readOnly: true + ## + extraVolumeMounts: [] + ## @param arbiter.extraVolumes Optionally specify extra list of additional volumes to the Arbiter statefulset + ## extraVolumes: + ## - name: extras + ## emptyDir: {} + ## + extraVolumes: [] + ## MongoDB(®) Arbiter Pod Disruption Budget configuration + ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/ + ## + pdb: + ## @param arbiter.pdb.create Enable/disable a Pod Disruption Budget creation for Arbiter pod(s) + ## + create: false + ## @param arbiter.pdb.minAvailable Minimum number/percentage of Arbiter pods that should remain scheduled + ## + minAvailable: 1 + ## @param arbiter.pdb.maxUnavailable Maximum number/percentage of Arbiter pods that may be made unavailable + ## + maxUnavailable: "" + ## MongoDB(®) Arbiter service parameters + ## + service: + ## @param arbiter.service.nameOverride The arbiter service name + ## + nameOverride: "" + ## @param arbiter.service.ports.mongodb MongoDB(®) service port + ## + ports: + mongodb: 27017 + ## @param arbiter.service.extraPorts Extra ports to expose (normally used with the `sidecar` value) + ## + extraPorts: [] + ## @param arbiter.service.annotations Provide any additional annotations that may be required + ## + annotations: {} + +## @section Hidden Node parameters +## + +hidden: + ## @param hidden.enabled Enable deploying the hidden nodes + ## https://docs.mongodb.com/manual/tutorial/configure-a-hidden-replica-set-member/ + ## + enabled: false + ## @param hidden.hostAliases Add deployment host aliases + ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ + ## + hostAliases: [] + ## @param hidden.configuration Hidden node configuration file to be used + ## http://docs.mongodb.org/manual/reference/configuration-options/ + ## + configuration: "" + ## @param hidden.existingConfigmap Name of existing ConfigMap with Hidden node configuration + ## NOTE: When it's set the hidden.configuration parameter is ignored + ## + existingConfigmap: "" + ## Command and args for running the container (set to default if not set). Use array form + ## @param hidden.command Override default container command (useful when using custom images) + ## @param hidden.args Override default container args (useful when using custom images) + ## + command: [] + args: [] + ## @param hidden.extraFlags Hidden node additional command line flags + ## Example: + ## extraFlags: + ## - "--wiredTigerCacheSizeGB=2" + ## + extraFlags: [] + ## @param hidden.extraEnvVars Extra environment variables to add to Hidden node pods + ## E.g: + ## extraEnvVars: + ## - name: FOO + ## value: BAR + ## + extraEnvVars: [] + ## @param hidden.extraEnvVarsCM Name of existing ConfigMap containing extra env vars + ## + extraEnvVarsCM: "" + ## @param hidden.extraEnvVarsSecret Name of existing Secret containing extra env vars (in case of sensitive data) + ## + extraEnvVarsSecret: "" + ## @param hidden.annotations Additional labels to be added to thehidden node statefulset + ## + annotations: {} + ## @param hidden.labels Annotations to be added to the hidden node statefulset + ## + labels: {} + ## @param hidden.topologySpreadConstraints MongoDB(®) Spread Constraints for hidden Pods + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ + ## + topologySpreadConstraints: [] + ## @param hidden.lifecycleHooks LifecycleHook for the Hidden container to automate configuration before or after startup + ## + lifecycleHooks: {} + ## @param hidden.replicaCount Number of hidden nodes (only when `architecture=replicaset`) + ## Ignored when mongodb.architecture=standalone + ## + replicaCount: 1 + ## @param hidden.terminationGracePeriodSeconds Hidden Termination Grace Period + ## + terminationGracePeriodSeconds: "" + ## @param hidden.updateStrategy.type Strategy that will be employed to update Pods in the StatefulSet + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies + ## updateStrategy: + ## type: RollingUpdate + ## rollingUpdate: + ## maxSurge: 25% + ## maxUnavailable: 25% + ## + updateStrategy: + type: RollingUpdate + ## @param hidden.podManagementPolicy Pod management policy for hidden node + ## + podManagementPolicy: OrderedReady + ## @param hidden.schedulerName Name of the scheduler (other than default) to dispatch pods + ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ + ## + schedulerName: "" + ## @param hidden.podAffinityPreset Hidden node Pod affinity preset. Ignored if `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 hidden.podAntiAffinityPreset Hidden node Pod anti-affinity preset. Ignored if `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 + ## Node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## Allowed values: soft, hard + ## + nodeAffinityPreset: + ## @param hidden.nodeAffinityPreset.type Hidden Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` + ## + type: "" + ## @param hidden.nodeAffinityPreset.key Hidden Node label key to match Ignored if `affinity` is set. + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## @param hidden.nodeAffinityPreset.values Hidden Node label values to match. Ignored if `affinity` is set. + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + ## @param hidden.affinity Hidden node Affinity for pod 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 hidden.nodeSelector Hidden node Node labels for pod assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + ## @param hidden.tolerations Hidden node Tolerations for pod assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + ## @param hidden.podLabels Hidden node pod labels + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + ## + podLabels: {} + ## @param hidden.podAnnotations Hidden node Pod annotations + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + podAnnotations: {} + ## @param hidden.priorityClassName Name of the existing priority class to be used by hidden node pod(s) + ## ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ + ## + priorityClassName: "" + ## @param hidden.runtimeClassName Name of the runtime class to be used by hidden node pod(s) + ## ref: https://kubernetes.io/docs/concepts/containers/runtime-class/ + ## + runtimeClassName: "" + ## MongoDB(®) Hidden pods' Security Context. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod + ## @param hidden.podSecurityContext.enabled Enable Hidden pod(s)' Security Context + ## @param hidden.podSecurityContext.fsGroup Group ID for the volumes of the Hidden pod(s) + ## @param hidden.podSecurityContext.sysctls sysctl settings of the Hidden pod(s)' + ## + podSecurityContext: + enabled: true + fsGroup: 1001 + ## sysctl settings + ## Example: + ## sysctls: + ## - name: net.core.somaxconn + ## value: "10000" + ## + sysctls: [] + ## MongoDB(®) Hidden containers' Security Context (only main container). + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + ## @param hidden.containerSecurityContext.enabled Enable Hidden container(s)' Security Context + ## @param hidden.containerSecurityContext.runAsUser User ID for the Hidden container + ## @param hidden.containerSecurityContext.runAsNonRoot Set Hidden containers' Security Context runAsNonRoot + ## + containerSecurityContext: + enabled: true + runAsUser: 1001 + runAsNonRoot: true + ## MongoDB(®) Hidden containers' 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 hidden.resources.limits The resources limits for hidden node containers + ## @param hidden.resources.requests The requested resources for hidden node containers + ## + resources: + ## Example: + ## limits: + ## cpu: 100m + ## memory: 128Mi + ## + limits: {} + ## Examples: + ## requests: + ## cpu: 100m + ## memory: 128Mi + ## + requests: {} + ## @param hidden.containerPorts.mongodb MongoDB(®) hidden container port + containerPorts: + mongodb: 27017 + ## MongoDB(®) Hidden pods' liveness probe. Evaluated as a template. + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes + ## @param hidden.livenessProbe.enabled Enable livenessProbe + ## @param hidden.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe + ## @param hidden.livenessProbe.periodSeconds Period seconds for livenessProbe + ## @param hidden.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe + ## @param hidden.livenessProbe.failureThreshold Failure threshold for livenessProbe + ## @param hidden.livenessProbe.successThreshold Success threshold for livenessProbe + ## + livenessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 20 + timeoutSeconds: 10 + failureThreshold: 6 + successThreshold: 1 + ## MongoDB(®) Hidden pods' readiness probe. Evaluated as a template. + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes + ## @param hidden.readinessProbe.enabled Enable readinessProbe + ## @param hidden.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe + ## @param hidden.readinessProbe.periodSeconds Period seconds for readinessProbe + ## @param hidden.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe + ## @param hidden.readinessProbe.failureThreshold Failure threshold for readinessProbe + ## @param hidden.readinessProbe.successThreshold Success threshold for readinessProbe + ## + readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 20 + timeoutSeconds: 10 + failureThreshold: 6 + successThreshold: 1 + ## Slow starting containers can be protected through startup probes + ## Startup probes are available in Kubernetes version 1.16 and above + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-startup-probes + ## @param hidden.startupProbe.enabled Enable startupProbe + ## @param hidden.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe + ## @param hidden.startupProbe.periodSeconds Period seconds for startupProbe + ## @param hidden.startupProbe.timeoutSeconds Timeout seconds for startupProbe + ## @param hidden.startupProbe.failureThreshold Failure threshold for startupProbe + ## @param hidden.startupProbe.successThreshold Success threshold for startupProbe + ## + startupProbe: + enabled: false + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 30 + ## @param hidden.customLivenessProbe Override default liveness probe for hidden node containers + ## Ignored when hidden.livenessProbe.enabled=true + ## + customLivenessProbe: {} + ## @param hidden.customReadinessProbe Override default readiness probe for hidden node containers + ## Ignored when hidden.readinessProbe.enabled=true + ## + customReadinessProbe: {} + ## @param hidden.customStartupProbe Override default startup probe for MongoDB(®) containers + ## Ignored when hidden.startupProbe.enabled=true + ## + customStartupProbe: {} + ## @param hidden.initContainers Add init containers to the MongoDB(®) Hidden pods. + ## Example: + ## initContainers: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + initContainers: [] + ## @param hidden.sidecars Add additional sidecar containers for the hidden node pod(s) + ## Example: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + ## @param hidden.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the hidden node container(s) + ## Examples: + ## extraVolumeMounts: + ## - name: extras + ## mountPath: /usr/share/extras + ## readOnly: true + ## + extraVolumeMounts: [] + ## @param hidden.extraVolumes Optionally specify extra list of additional volumes to the hidden node statefulset + ## extraVolumes: + ## - name: extras + ## emptyDir: {} + ## + extraVolumes: [] + ## MongoDB(®) Hidden Pod Disruption Budget configuration + ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/ + ## + pdb: + ## @param hidden.pdb.create Enable/disable a Pod Disruption Budget creation for hidden node pod(s) + ## + create: false + ## @param hidden.pdb.minAvailable Minimum number/percentage of hidden node pods that should remain scheduled + ## + minAvailable: 1 + ## @param hidden.pdb.maxUnavailable Maximum number/percentage of hidden node pods that may be made unavailable + ## + maxUnavailable: "" + ## Enable persistence using Persistent Volume Claims + ## ref: https://kubernetes.io/docs/user-guide/persistent-volumes/ + ## + persistence: + ## @param hidden.persistence.enabled Enable hidden node data persistence using PVC + ## + enabled: true + ## @param hidden.persistence.medium Provide a medium for `emptyDir` volumes. + ## Requires hidden.persistence.enabled: false + ## + medium: "" + ## @param hidden.persistence.storageClass PVC Storage Class for hidden node data volume + ## 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. + ## + storageClass: "" + ## @param hidden.persistence.accessModes PV Access Mode + ## + accessModes: + - ReadWriteOnce + ## @param hidden.persistence.size PVC Storage Request for hidden node data volume + ## + size: 8Gi + ## @param hidden.persistence.annotations PVC annotations + ## + annotations: {} + ## @param hidden.persistence.mountPath The path the volume will be mounted at, useful when using different MongoDB(®) images. + ## + mountPath: /bitnami/mongodb + ## @param hidden.persistence.subPath The subdirectory of the volume to mount to, useful in dev environments + ## and one PV for multiple services. + ## + subPath: "" + ## Fine tuning for volumeClaimTemplates + ## + volumeClaimTemplates: + ## @param hidden.persistence.volumeClaimTemplates.selector A label query over volumes to consider for binding (e.g. when using local volumes) + ## See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#labelselector-v1-meta for more details + ## + selector: {} + ## @param hidden.persistence.volumeClaimTemplates.requests Custom PVC requests attributes + ## Sometime cloud providers use additional requests attributes to provision custom storage instance + ## See https://cloud.ibm.com/docs/containers?topic=containers-file_storage#file_dynamic_statefulset + ## + requests: {} + ## @param hidden.persistence.volumeClaimTemplates.dataSource Set volumeClaimTemplate dataSource + ## + dataSource: {} + service: + ## @param hidden.service.portName MongoDB(®) service port name + ## + portName: "mongodb" + ## @param hidden.service.ports.mongodb MongoDB(®) service port + ## + ports: + mongodb: 27017 + ## @param hidden.service.extraPorts Extra ports to expose (normally used with the `sidecar` value) + ## + extraPorts: [] + ## @param hidden.service.annotations Provide any additional annotations that may be required + ## + annotations: {} + +## @section Metrics parameters +## + +metrics: + ## @param metrics.enabled Enable using a sidecar Prometheus exporter + ## + enabled: false + ## Bitnami MongoDB(®) Promtheus Exporter image + ## ref: https://hub.docker.com/r/bitnami/mongodb-exporter/tags/ + ## @param metrics.image.registry MongoDB(®) Prometheus exporter image registry + ## @param metrics.image.repository MongoDB(®) Prometheus exporter image repository + ## @param metrics.image.tag MongoDB(®) Prometheus exporter image tag (immutable tags are recommended) + ## @param metrics.image.digest MongoDB(®) image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag + ## @param metrics.image.pullPolicy MongoDB(®) Prometheus exporter image pull policy + ## @param metrics.image.pullSecrets Specify docker-registry secret names as an array + ## + image: + registry: docker.io + repository: bitnami/mongodb-exporter + tag: 0.35.0-debian-11-r14 + 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/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + + ## @param metrics.username String with username for the metrics exporter + ## If undefined the root user will be used for the metrics exporter + username: "" + ## @param metrics.password String with password for the metrics exporter + ## If undefined but metrics.username is defined, a random password will be generated + password: "" + ## @param metrics.extraFlags String with extra flags to the metrics exporter + ## ref: https://github.com/percona/mongodb_exporter/blob/master/mongodb_exporter.go + ## + extraFlags: "" + ## Command and args for running the container (set to default if not set). Use array form + ## @param metrics.command Override default container command (useful when using custom images) + ## @param metrics.args Override default container args (useful when using custom images) + ## + command: [] + args: [] + ## Metrics exporter container 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 Prometheus exporter containers + ## @param metrics.resources.requests The requested resources for Prometheus exporter containers + ## + resources: + ## Example: + ## limits: + ## cpu: 100m + ## memory: 128Mi + ## + limits: {} + ## Examples: + ## requests: + ## cpu: 100m + ## memory: 128Mi + ## + requests: {} + ## @param metrics.containerPort Port of the Prometheus metrics container + ## + containerPort: 9216 + ## Prometheus Exporter service configuration + ## + service: + ## @param metrics.service.annotations [object] Annotations for Prometheus Exporter pods. Evaluated as a template. + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "{{ .Values.metrics.service.ports.metrics }}" + prometheus.io/path: "/metrics" + ## @param metrics.service.type Type of the Prometheus metrics service + ## + type: ClusterIP + ## @param metrics.service.ports.metrics Port of the Prometheus metrics service + ## + ports: + metrics: 9216 + ## @param metrics.service.extraPorts Extra ports to expose (normally used with the `sidecar` value) + ## + extraPorts: [] + ## Metrics exporter 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: 15 + periodSeconds: 5 + timeoutSeconds: 5 + failureThreshold: 3 + successThreshold: 1 + ## Metrics exporter 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: 5 + periodSeconds: 5 + timeoutSeconds: 1 + failureThreshold: 3 + successThreshold: 1 + ## Slow starting containers can be protected through startup probes + ## Startup probes are available in Kubernetes version 1.16 and above + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-startup-probes + ## @param metrics.startupProbe.enabled Enable startupProbe + ## @param metrics.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe + ## @param metrics.startupProbe.periodSeconds Period seconds for startupProbe + ## @param metrics.startupProbe.timeoutSeconds Timeout seconds for startupProbe + ## @param metrics.startupProbe.failureThreshold Failure threshold for startupProbe + ## @param metrics.startupProbe.successThreshold Success threshold for startupProbe + ## + startupProbe: + enabled: false + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 30 + ## @param metrics.customLivenessProbe Override default liveness probe for MongoDB(®) containers + ## Ignored when livenessProbe.enabled=true + ## + customLivenessProbe: {} + ## @param metrics.customReadinessProbe Override default readiness probe for MongoDB(®) containers + ## Ignored when readinessProbe.enabled=true + ## + customReadinessProbe: {} + ## @param metrics.customStartupProbe Override default startup probe for MongoDB(®) containers + ## Ignored when startupProbe.enabled=true + ## + customStartupProbe: {} + ## Prometheus Service Monitor + ## ref: https://github.com/coreos/prometheus-operator + ## https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md + ## + serviceMonitor: + ## @param metrics.serviceMonitor.enabled Create ServiceMonitor Resource for scraping metrics using Prometheus Operator + ## + enabled: false + ## @param metrics.serviceMonitor.namespace Namespace which Prometheus is running in + ## + namespace: "" + ## @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. + ## + relabelings: [] + ## @param metrics.serviceMonitor.metricRelabelings MetricsRelabelConfigs to apply to samples before ingestion. + ## + metricRelabelings: [] + ## @param metrics.serviceMonitor.labels Used to pass Labels that are used by the Prometheus installed in your cluster to select Service Monitors to work with + ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#prometheusspec + ## + labels: {} + ## @param metrics.serviceMonitor.selector Prometheus instance selector labels + ## ref: https://github.com/bitnami/charts/tree/main/bitnami/prometheus-operator#prometheus-configuration + ## + selector: {} + ## @param metrics.serviceMonitor.honorLabels Specify honorLabels parameter to add the scrape endpoint + ## + honorLabels: false + ## @param metrics.serviceMonitor.jobLabel The name of the label on the target service to use as the job name in prometheus. + ## + jobLabel: "" + ## Custom PrometheusRule to be defined + ## ref: https://github.com/coreos/prometheus-operator#customresourcedefinitions + ## + prometheusRule: + ## @param metrics.prometheusRule.enabled Set this to true to create prometheusRules for Prometheus operator + ## + enabled: false + ## @param metrics.prometheusRule.additionalLabels Additional labels that can be used so prometheusRules will be discovered by Prometheus + ## + additionalLabels: {} + ## @param metrics.prometheusRule.namespace Namespace where prometheusRules resource should be created + ## + namespace: "" + ## @param metrics.prometheusRule.rules Rules to be created, check values for an example + ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#rulegroup + ## https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/ + ## + ## This is an example of a rule, you should add the below code block under the "rules" param, removing the brackets + ## rules: + ## - alert: HighRequestLatency + ## expr: job:request_latency_seconds:mean5m{job="myjob"} > 0.5 + ## for: 10m + ## labels: + ## severity: page + ## annotations: + ## summary: High request latency + ## + rules: [] diff --git a/deployment/deployment/nginx-ingress-controller/.helmignore b/deployment/charts/mysql/.helmignore similarity index 100% rename from deployment/deployment/nginx-ingress-controller/.helmignore rename to deployment/charts/mysql/.helmignore diff --git a/deployment/charts/mysql/Chart.lock b/deployment/charts/mysql/Chart.lock new file mode 100644 index 0000000..485cbc3 --- /dev/null +++ b/deployment/charts/mysql/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common + repository: https://charts.bitnami.com/bitnami + version: 2.2.2 +digest: sha256:49ca75cf23ba5eb7df4becef52580f98c8bd8194eb80368b9d7b875f6eefa8e5 +generated: "2023-01-09T03:04:58.278003695Z" diff --git a/deployment/charts/mysql/Chart.yaml b/deployment/charts/mysql/Chart.yaml new file mode 100644 index 0000000..0f7879f --- /dev/null +++ b/deployment/charts/mysql/Chart.yaml @@ -0,0 +1,28 @@ +annotations: + category: Database +apiVersion: v2 +appVersion: 8.0.31 +dependencies: +- name: common + repository: https://charts.bitnami.com/bitnami + tags: + - bitnami-common + version: 2.x.x +description: MySQL is a fast, reliable, scalable, and easy to use open source relational + database system. Designed to handle mission-critical, heavy-load production applications. +home: https://github.com/bitnami/charts/tree/main/bitnami/mysql +icon: https://bitnami.com/assets/stacks/mysql/img/mysql-stack-220x234.png +keywords: +- mysql +- database +- sql +- cluster +- high availability +maintainers: +- name: Bitnami + url: https://github.com/bitnami/charts +name: mysql +sources: +- https://github.com/bitnami/containers/tree/main/bitnami/mysql +- https://mysql.com +version: 9.4.6 diff --git a/deployment/charts/mysql/README.md b/deployment/charts/mysql/README.md new file mode 100644 index 0000000..8efabf0 --- /dev/null +++ b/deployment/charts/mysql/README.md @@ -0,0 +1,554 @@ + + +# MySQL packaged by Bitnami + +MySQL is a fast, reliable, scalable, and easy to use open source relational database system. Designed to handle mission-critical, heavy-load production applications. + +[Overview of MySQL](http://www.mysql.com) + +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/mysql +``` + +## Introduction + +This chart bootstraps a [MySQL](https://github.com/bitnami/containers/tree/main/bitnami/mysql) replication cluster deployment on a [Kubernetes](https://kubernetes.io) cluster using the [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+ +- PV provisioner support in the underlying infrastructure + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```bash +$ helm repo add my-repo https://charts.bitnami.com/bitnami +$ helm install my-release my-repo/mysql +``` + +These commands deploy MySQL 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 StorageClass for Persistent Volume(s) | `""` | + + +### Common parameters + +| Name | Description | Value | +| ------------------------ | --------------------------------------------------------------------------------------------------------- | --------------- | +| `kubeVersion` | Force target Kubernetes version (using Helm capabilities if not set) | `""` | +| `nameOverride` | String to partially override common.names.fullname template (will maintain the release name) | `""` | +| `fullnameOverride` | String to fully override common.names.fullname template | `""` | +| `namespaceOverride` | String to fully override common.names.namespace | `""` | +| `clusterDomain` | Cluster domain | `cluster.local` | +| `commonAnnotations` | Common annotations to add to all MySQL resources (sub-charts are not considered). Evaluated as a template | `{}` | +| `commonLabels` | Common labels to add to all MySQL resources (sub-charts are not considered). Evaluated as a template | `{}` | +| `extraDeploy` | Array with extra yaml to deploy with the chart. 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"]` | + + +### MySQL common parameters + +| Name | Description | Value | +| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | +| `image.registry` | MySQL image registry | `docker.io` | +| `image.repository` | MySQL image repository | `bitnami/mysql` | +| `image.tag` | MySQL image tag (immutable tags are recommended) | `8.0.31-debian-11-r30` | +| `image.digest` | MySQL image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | +| `image.pullPolicy` | MySQL 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` | MySQL architecture (`standalone` or `replication`) | `standalone` | +| `auth.rootPassword` | Password for the `root` user. Ignored if existing secret is provided | `""` | +| `auth.createDatabase` | Wheter to create the .Values.auth.database or not | `true` | +| `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` | MySQL replication user | `replicator` | +| `auth.replicationPassword` | MySQL replication user password. Ignored if existing secret is provided | `""` | +| `auth.existingSecret` | Use existing secret for password details. The secret has to contain the keys `mysql-root-password`, `mysql-replication-password` and `mysql-password` | `""` | +| `auth.usePasswordFiles` | Mount credentials as files instead of using an environment variable | `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`) | `""` | + + +### MySQL Primary parameters + +| Name | Description | Value | +| ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------- | +| `primary.name` | Name of the primary database (eg primary, master, leader, ...) | `primary` | +| `primary.command` | Override default container command on MySQL Primary container(s) (useful when using custom images) | `[]` | +| `primary.args` | Override default container args on MySQL Primary container(s) (useful when using custom images) | `[]` | +| `primary.lifecycleHooks` | for the MySQL Primary container(s) to automate configuration before or after startup | `{}` | +| `primary.hostAliases` | Deployment pod host aliases | `[]` | +| `primary.configuration` | Configure MySQL Primary with a custom my.cnf file | `""` | +| `primary.existingConfigmap` | Name of existing ConfigMap with MySQL Primary configuration. | `""` | +| `primary.updateStrategy.type` | Update strategy type for the MySQL primary statefulset | `RollingUpdate` | +| `primary.podAnnotations` | Additional pod annotations for MySQL primary pods | `{}` | +| `primary.podAffinityPreset` | MySQL primary pod affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `primary.podAntiAffinityPreset` | MySQL primary pod anti-affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `primary.nodeAffinityPreset.type` | MySQL primary node affinity preset type. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `primary.nodeAffinityPreset.key` | MySQL primary node label key to match Ignored if `primary.affinity` is set. | `""` | +| `primary.nodeAffinityPreset.values` | MySQL primary node label values to match. Ignored if `primary.affinity` is set. | `[]` | +| `primary.affinity` | Affinity for MySQL primary pods assignment | `{}` | +| `primary.nodeSelector` | Node labels for MySQL primary pods assignment | `{}` | +| `primary.tolerations` | Tolerations for MySQL primary pods assignment | `[]` | +| `primary.priorityClassName` | MySQL primary pods' priorityClassName | `""` | +| `primary.runtimeClassName` | MySQL primary pods' runtimeClassName | `""` | +| `primary.schedulerName` | Name of the k8s scheduler (other than default) | `""` | +| `primary.terminationGracePeriodSeconds` | In seconds, time the given to the MySQL primary pod needs to terminate gracefully | `""` | +| `primary.topologySpreadConstraints` | Topology Spread Constraints for pod assignment | `[]` | +| `primary.podManagementPolicy` | podManagementPolicy to manage scaling operation of MySQL primary pods | `""` | +| `primary.podSecurityContext.enabled` | Enable security context for MySQL primary pods | `true` | +| `primary.podSecurityContext.fsGroup` | Group ID for the mounted volumes' filesystem | `1001` | +| `primary.containerSecurityContext.enabled` | MySQL primary container securityContext | `true` | +| `primary.containerSecurityContext.runAsUser` | User ID for the MySQL primary container | `1001` | +| `primary.containerSecurityContext.runAsNonRoot` | Set MySQL primary container's Security Context runAsNonRoot | `true` | +| `primary.resources.limits` | The resources limits for MySQL primary containers | `{}` | +| `primary.resources.requests` | The requested resources for MySQL primary containers | `{}` | +| `primary.livenessProbe.enabled` | Enable livenessProbe | `true` | +| `primary.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `5` | +| `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 | `5` | +| `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.startupProbe.enabled` | Enable startupProbe | `true` | +| `primary.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `15` | +| `primary.startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | +| `primary.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `1` | +| `primary.startupProbe.failureThreshold` | Failure threshold for startupProbe | `10` | +| `primary.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | +| `primary.customLivenessProbe` | Override default liveness probe for MySQL primary containers | `{}` | +| `primary.customReadinessProbe` | Override default readiness probe for MySQL primary containers | `{}` | +| `primary.customStartupProbe` | Override default startup probe for MySQL primary containers | `{}` | +| `primary.extraFlags` | MySQL primary additional command line flags | `""` | +| `primary.extraEnvVars` | Extra environment variables to be set on MySQL primary containers | `[]` | +| `primary.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for MySQL primary containers | `""` | +| `primary.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for MySQL primary containers | `""` | +| `primary.persistence.enabled` | Enable persistence on MySQL primary replicas using a `PersistentVolumeClaim`. If false, use emptyDir | `true` | +| `primary.persistence.existingClaim` | Name of an existing `PersistentVolumeClaim` for MySQL primary replicas | `""` | +| `primary.persistence.subPath` | The name of a volume's sub path to mount for persistence | `""` | +| `primary.persistence.storageClass` | MySQL primary persistent volume storage Class | `""` | +| `primary.persistence.annotations` | MySQL primary persistent volume claim annotations | `{}` | +| `primary.persistence.accessModes` | MySQL primary persistent volume access Modes | `["ReadWriteOnce"]` | +| `primary.persistence.size` | MySQL 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 MySQL Primary pod(s) | `[]` | +| `primary.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the MySQL Primary container(s) | `[]` | +| `primary.initContainers` | Add additional init containers for the MySQL Primary pod(s) | `[]` | +| `primary.sidecars` | Add additional sidecar containers for the MySQL Primary pod(s) | `[]` | +| `primary.service.type` | MySQL Primary K8s service type | `ClusterIP` | +| `primary.service.ports.mysql` | MySQL Primary K8s service port | `3306` | +| `primary.service.nodePorts.mysql` | MySQL Primary K8s service node port | `""` | +| `primary.service.clusterIP` | MySQL Primary K8s service clusterIP IP | `""` | +| `primary.service.loadBalancerIP` | MySQL Primary loadBalancerIP if service type is `LoadBalancer` | `""` | +| `primary.service.externalTrafficPolicy` | Enable client source IP preservation | `Cluster` | +| `primary.service.loadBalancerSourceRanges` | Addresses that are allowed when MySQL Primary service is LoadBalancer | `[]` | +| `primary.service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | +| `primary.service.annotations` | Additional custom annotations for MySQL primary service | `{}` | +| `primary.service.sessionAffinity` | Session Affinity for Kubernetes service, can be "None" or "ClientIP" | `None` | +| `primary.service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | +| `primary.service.headless.annotations` | Additional custom annotations for headless MySQL primary service. | `{}` | +| `primary.pdb.create` | Enable/disable a Pod Disruption Budget creation for MySQL primary pods | `false` | +| `primary.pdb.minAvailable` | Minimum number/percentage of MySQL primary pods that should remain scheduled | `1` | +| `primary.pdb.maxUnavailable` | Maximum number/percentage of MySQL primary pods that may be made unavailable | `""` | +| `primary.podLabels` | MySQL Primary pod label. If labels are same as commonLabels , this will take precedence | `{}` | + + +### MySQL Secondary parameters + +| Name | Description | Value | +| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------- | +| `secondary.name` | Name of the secondary database (eg secondary, slave, ...) | `secondary` | +| `secondary.replicaCount` | Number of MySQL secondary replicas | `1` | +| `secondary.hostAliases` | Deployment pod host aliases | `[]` | +| `secondary.command` | Override default container command on MySQL Secondary container(s) (useful when using custom images) | `[]` | +| `secondary.args` | Override default container args on MySQL Secondary container(s) (useful when using custom images) | `[]` | +| `secondary.lifecycleHooks` | for the MySQL Secondary container(s) to automate configuration before or after startup | `{}` | +| `secondary.configuration` | Configure MySQL Secondary with a custom my.cnf file | `""` | +| `secondary.existingConfigmap` | Name of existing ConfigMap with MySQL Secondary configuration. | `""` | +| `secondary.updateStrategy.type` | Update strategy type for the MySQL secondary statefulset | `RollingUpdate` | +| `secondary.podAnnotations` | Additional pod annotations for MySQL secondary pods | `{}` | +| `secondary.podAffinityPreset` | MySQL secondary pod affinity preset. Ignored if `secondary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `secondary.podAntiAffinityPreset` | MySQL secondary pod anti-affinity preset. Ignored if `secondary.affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `secondary.nodeAffinityPreset.type` | MySQL secondary node affinity preset type. Ignored if `secondary.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `secondary.nodeAffinityPreset.key` | MySQL secondary node label key to match Ignored if `secondary.affinity` is set. | `""` | +| `secondary.nodeAffinityPreset.values` | MySQL secondary node label values to match. Ignored if `secondary.affinity` is set. | `[]` | +| `secondary.affinity` | Affinity for MySQL secondary pods assignment | `{}` | +| `secondary.nodeSelector` | Node labels for MySQL secondary pods assignment | `{}` | +| `secondary.tolerations` | Tolerations for MySQL secondary pods assignment | `[]` | +| `secondary.priorityClassName` | MySQL secondary pods' priorityClassName | `""` | +| `secondary.runtimeClassName` | MySQL secondary pods' runtimeClassName | `""` | +| `secondary.schedulerName` | Name of the k8s scheduler (other than default) | `""` | +| `secondary.terminationGracePeriodSeconds` | In seconds, time the given to the MySQL secondary pod needs to terminate gracefully | `""` | +| `secondary.topologySpreadConstraints` | Topology Spread Constraints for pod assignment | `[]` | +| `secondary.podManagementPolicy` | podManagementPolicy to manage scaling operation of MySQL secondary pods | `""` | +| `secondary.podSecurityContext.enabled` | Enable security context for MySQL secondary pods | `true` | +| `secondary.podSecurityContext.fsGroup` | Group ID for the mounted volumes' filesystem | `1001` | +| `secondary.containerSecurityContext.enabled` | MySQL secondary container securityContext | `true` | +| `secondary.containerSecurityContext.runAsUser` | User ID for the MySQL secondary container | `1001` | +| `secondary.containerSecurityContext.runAsNonRoot` | Set MySQL secondary container's Security Context runAsNonRoot | `true` | +| `secondary.resources.limits` | The resources limits for MySQL secondary containers | `{}` | +| `secondary.resources.requests` | The requested resources for MySQL secondary containers | `{}` | +| `secondary.livenessProbe.enabled` | Enable livenessProbe | `true` | +| `secondary.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `5` | +| `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 | `5` | +| `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.startupProbe.enabled` | Enable startupProbe | `true` | +| `secondary.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `15` | +| `secondary.startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | +| `secondary.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `1` | +| `secondary.startupProbe.failureThreshold` | Failure threshold for startupProbe | `15` | +| `secondary.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | +| `secondary.customLivenessProbe` | Override default liveness probe for MySQL secondary containers | `{}` | +| `secondary.customReadinessProbe` | Override default readiness probe for MySQL secondary containers | `{}` | +| `secondary.customStartupProbe` | Override default startup probe for MySQL secondary containers | `{}` | +| `secondary.extraFlags` | MySQL secondary additional command line flags | `""` | +| `secondary.extraEnvVars` | An array to add extra environment variables on MySQL secondary containers | `[]` | +| `secondary.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for MySQL secondary containers | `""` | +| `secondary.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for MySQL secondary containers | `""` | +| `secondary.persistence.enabled` | Enable persistence on MySQL secondary replicas using a `PersistentVolumeClaim` | `true` | +| `secondary.persistence.existingClaim` | Name of an existing `PersistentVolumeClaim` for MySQL secondary replicas | `""` | +| `secondary.persistence.subPath` | The name of a volume's sub path to mount for persistence | `""` | +| `secondary.persistence.storageClass` | MySQL secondary persistent volume storage Class | `""` | +| `secondary.persistence.annotations` | MySQL secondary persistent volume claim annotations | `{}` | +| `secondary.persistence.accessModes` | MySQL secondary persistent volume access Modes | `["ReadWriteOnce"]` | +| `secondary.persistence.size` | MySQL 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 MySQL secondary pod(s) | `[]` | +| `secondary.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the MySQL secondary container(s) | `[]` | +| `secondary.initContainers` | Add additional init containers for the MySQL secondary pod(s) | `[]` | +| `secondary.sidecars` | Add additional sidecar containers for the MySQL secondary pod(s) | `[]` | +| `secondary.service.type` | MySQL secondary Kubernetes service type | `ClusterIP` | +| `secondary.service.ports.mysql` | MySQL secondary Kubernetes service port | `3306` | +| `secondary.service.nodePorts.mysql` | MySQL secondary Kubernetes service node port | `""` | +| `secondary.service.clusterIP` | MySQL secondary Kubernetes service clusterIP IP | `""` | +| `secondary.service.loadBalancerIP` | MySQL secondary loadBalancerIP if service type is `LoadBalancer` | `""` | +| `secondary.service.externalTrafficPolicy` | Enable client source IP preservation | `Cluster` | +| `secondary.service.loadBalancerSourceRanges` | Addresses that are allowed when MySQL secondary service is LoadBalancer | `[]` | +| `secondary.service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | +| `secondary.service.annotations` | Additional custom annotations for MySQL secondary service | `{}` | +| `secondary.service.sessionAffinity` | Session Affinity for Kubernetes service, can be "None" or "ClientIP" | `None` | +| `secondary.service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | +| `secondary.service.headless.annotations` | Additional custom annotations for headless MySQL secondary service. | `{}` | +| `secondary.pdb.create` | Enable/disable a Pod Disruption Budget creation for MySQL secondary pods | `false` | +| `secondary.pdb.minAvailable` | Minimum number/percentage of MySQL secondary pods that should remain scheduled | `1` | +| `secondary.pdb.maxUnavailable` | Maximum number/percentage of MySQL secondary pods that may be made unavailable | `""` | +| `secondary.podLabels` | Additional pod labels for MySQL secondary pods | `{}` | + + +### RBAC parameters + +| Name | Description | Value | +| --------------------------------------------- | -------------------------------------------------------------- | ------- | +| `serviceAccount.create` | Enable the creation of a ServiceAccount for MySQL pods | `true` | +| `serviceAccount.name` | Name of the created ServiceAccount | `""` | +| `serviceAccount.annotations` | Annotations for MySQL Service Account | `{}` | +| `serviceAccount.automountServiceAccountToken` | Automount service account token for the server service account | `true` | +| `rbac.create` | Whether to create & use RBAC resources or not | `false` | +| `rbac.rules` | Custom RBAC rules to set | `[]` | + + +### Network Policy + +| Name | Description | Value | +| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------- | ------- | +| `networkPolicy.enabled` | Enable creation of NetworkPolicy resources | `false` | +| `networkPolicy.allowExternal` | The Policy model to apply. | `true` | +| `networkPolicy.explicitNamespacesSelector` | A Kubernetes LabelSelector to explicitly select namespaces from which ingress traffic could be allowed to MySQL | `{}` | + + +### 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-r70` | +| `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` | Init container volume-permissions resources | `{}` | + + +### 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-r76` | +| `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.service.type` | Kubernetes service type for MySQL Prometheus Exporter | `ClusterIP` | +| `metrics.service.port` | MySQL Prometheus Exporter service port | `9104` | +| `metrics.service.annotations` | Prometheus exporter service annotations | `{}` | +| `metrics.extraArgs.primary` | Extra args to be passed to mysqld_exporter on Primary pods | `[]` | +| `metrics.extraArgs.secondary` | Extra args to be passed to mysqld_exporter on Secondary pods | `[]` | +| `metrics.resources.limits` | The resources limits for MySQL prometheus exporter containers | `{}` | +| `metrics.resources.requests` | The requested resources for MySQL 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` | Specify the namespace in which the serviceMonitor resource will be created | `""` | +| `metrics.serviceMonitor.jobLabel` | The name of the label on the target service to use as the job name in prometheus. | `""` | +| `metrics.serviceMonitor.interval` | Specify the 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.selector` | ServiceMonitor selector labels | `{}` | +| `metrics.serviceMonitor.honorLabels` | Specify honorLabels parameter to add the scrape endpoint | `false` | +| `metrics.serviceMonitor.labels` | Used to pass Labels that are used by the Prometheus installed in your cluster to select Service Monitors to work with | `{}` | +| `metrics.serviceMonitor.annotations` | ServiceMonitor annotations | `{}` | +| `metrics.prometheusRule.enabled` | 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 | `[]` | + + +The above parameters map to the env variables defined in [bitnami/mysql](https://github.com/bitnami/containers/tree/main/bitnami/mysql). For more information please refer to the [bitnami/mysql](https://github.com/bitnami/containers/tree/main/bitnami/mysql) 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/mysql +``` + +The above command sets the MySQL `root` account password to `secretpassword`. Additionally it creates a database named `app_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/mysql +``` + +> **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. + +### Use a different MySQL version + +To modify the application version used in this chart, specify a different version of the image using the `image.tag` parameter and/or a different repository using the `image.repository` parameter. Refer to the [chart documentation for more information on these parameters and how to use them with images from a private registry](https://docs.bitnami.com/kubernetes/infrastructure/mysql/configuration/change-image-version/). + +### Customize a new MySQL instance + +The [Bitnami MySQL](https://github.com/bitnami/containers/tree/main/bitnami/mysql) 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](http://docs.bitnami.com/kubernetes/infrastructure/mysql/configuration/customize-new-instance/). + +### Sidecars and Init Containers + +If you have a need for additional containers to run within the same pod as MySQL, you can do so via the `sidecars` config parameter. Simply define your container according to the Kubernetes container spec. + +```yaml +sidecars: + - name: your-image-name + image: your-image + imagePullPolicy: Always + ports: + - name: portname + containerPort: 1234 +``` + +Similarly, you can add extra init containers using the `initContainers` parameter. + +```yaml +initContainers: + - name: your-image-name + image: your-image + imagePullPolicy: Always + ports: + - name: portname + containerPort: 1234 +``` + +## Persistence + +The [Bitnami MySQL](https://github.com/bitnami/containers/tree/main/bitnami/mysql) image stores the MySQL data and configurations at the `/bitnami/mysql` 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 for this purpose. + +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/). + +## Network Policy + +To enable network policy for MySQL, install [a networking plugin that implements the Kubernetes NetworkPolicy spec](https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy#before-you-begin), and set `networkPolicy.enabled` to `true`. + +For Kubernetes v1.5 & v1.6, you must also turn on NetworkPolicy by setting the DefaultDeny namespace annotation. Note: this will enforce policy for _all_ pods in the namespace: + +```console +$ kubectl annotate namespace default "net.beta.kubernetes.io/network-policy={\"ingress\":{\"isolation\":\"DefaultDeny\"}}" +``` + +With NetworkPolicy enabled, traffic will be limited to just port 3306. + +For more precise policy, set `networkPolicy.allowExternal=false`. This will only allow pods with the generated client label to connect to MySQL. +This label will be displayed in the output of a successful install. + +## Pod affinity + +This chart allows you to set your custom affinity using the `XXX.affinity` parameter(s). Find more information about Pod affinity in the [Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity). + +As an alternative, you can use the preset configurations for pod affinity, pod anti-affinity, and node affinity available at the [bitnami/common](https://github.com/bitnami/charts/tree/main/bitnami/common#affinities) chart. To do so, set the `XXX.podAffinityPreset`, `XXX.podAntiAffinityPreset`, or `XXX.nodeAffinityPreset` parameters. + +## 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/mysql --set auth.rootPassword=[ROOT_PASSWORD] +``` + +| Note: you need to substitute the placeholder _[ROOT_PASSWORD]_ with the value obtained in the installation notes. + +### To 9.0.0 + +This major release renames several values in this chart and adds missing features, in order to be aligned with the rest of the assets in the Bitnami charts repository. + +Affected values: + +- `schedulerName` was renamed as `primary.schedulerName` and `secondary.schedulerName`. +- The way how passwords are handled has been refactored and value `auth.forcePassword` has been removed. Now, the password configuration will have the following priority: + 1. Search for an already existing 'Secret' resource and reuse previous password. + 2. Password provided via the values.yaml + 3. If no secret existed, and no password was provided, the bitnami/mysql chart will set a randomly generated password. +- `primary.service.port` was renamed as `primary.service.ports.mysql`. +- `secondary.service.port` was renamed as `secondary.service.ports.mysql`. +- `primary.service.nodePort` was renamed as `primary.service.nodePorts.mysql`. +- `secondary.service.nodePort` was renamed as `secondary.service.nodePorts.mysql`. +- `primary.updateStrategy` and `secondary.updateStrategy` are now interpreted as an object and not a string. +- Values `primary.rollingUpdatePartition` and `secondary.rollingUpdatePartition` have been removed. In cases were they are needed, they can be set inside `.*updateStrategy`. +- `primary.pdb.enabled` was renamed as `primary.pdb.create`. +- `secondary.pdb.enabled` was renamed as `secondary.pdb.create`. +- `metrics.serviceMonitor.additionalLabels` was renamed as `metrics.serviceMonitor.labels` +- `metrics.serviceMonitor.relabellings` was removed, previously used to configured `metricRelabelings` field. We introduced two new values: `metrics.serviceMonitor.relabelings` and `metrics.serviceMonitor.metricRelabelings` that can be used to configured the serviceMonitor homonimous field. + +### 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. + - Credentials parameters are reorganized under the `auth` parameter. + - `replication.enabled` parameter is deprecated in favor of `architecture` parameter that accepts two values: `standalone` and `replication`. +- 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 MySQL 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://dev.mysql.com/doc/refman/8.0/en/mysqldump.html). + - 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 `mysql`: + +```bash +$ helm install mysql my-repo/mysql --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 + +[On November 13, 2020, Helm v2 support formally ended](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/mysql/administration/upgrade-helm3/). + +### To 3.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 3.0.0. The following example assumes that the release name is mysql: + +```console +$ kubectl delete statefulset mysql-master --cascade=false +$ kubectl delete statefulset mysql-slave --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/deployment/deployment/portalauth/.helmignore b/deployment/charts/mysql/charts/common/.helmignore similarity index 100% rename from deployment/deployment/portalauth/.helmignore rename to deployment/charts/mysql/charts/common/.helmignore diff --git a/deployment/charts/mysql/charts/common/Chart.yaml b/deployment/charts/mysql/charts/common/Chart.yaml new file mode 100644 index 0000000..f9ba944 --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/README.md b/deployment/charts/mysql/charts/common/README.md new file mode 100644 index 0000000..ec43a5f --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/_affinities.tpl b/deployment/charts/mysql/charts/common/templates/_affinities.tpl new file mode 100644 index 0000000..81902a6 --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/_capabilities.tpl b/deployment/charts/mysql/charts/common/templates/_capabilities.tpl new file mode 100644 index 0000000..9d9b760 --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/_errors.tpl b/deployment/charts/mysql/charts/common/templates/_errors.tpl new file mode 100644 index 0000000..a79cc2e --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/_images.tpl b/deployment/charts/mysql/charts/common/templates/_images.tpl new file mode 100644 index 0000000..46c659e --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/_ingress.tpl b/deployment/charts/mysql/charts/common/templates/_ingress.tpl new file mode 100644 index 0000000..831da9c --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/_labels.tpl b/deployment/charts/mysql/charts/common/templates/_labels.tpl new file mode 100644 index 0000000..252066c --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/_names.tpl b/deployment/charts/mysql/charts/common/templates/_names.tpl new file mode 100644 index 0000000..617a234 --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/_secrets.tpl b/deployment/charts/mysql/charts/common/templates/_secrets.tpl new file mode 100644 index 0000000..a1708b2 --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/_storage.tpl b/deployment/charts/mysql/charts/common/templates/_storage.tpl new file mode 100644 index 0000000..60e2a84 --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/_tplvalues.tpl b/deployment/charts/mysql/charts/common/templates/_tplvalues.tpl new file mode 100644 index 0000000..2db1668 --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/_utils.tpl b/deployment/charts/mysql/charts/common/templates/_utils.tpl new file mode 100644 index 0000000..b1ead50 --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/_warnings.tpl b/deployment/charts/mysql/charts/common/templates/_warnings.tpl new file mode 100644 index 0000000..ae10fa4 --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/validations/_cassandra.tpl b/deployment/charts/mysql/charts/common/templates/validations/_cassandra.tpl new file mode 100644 index 0000000..ded1ae3 --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/validations/_mariadb.tpl b/deployment/charts/mysql/charts/common/templates/validations/_mariadb.tpl new file mode 100644 index 0000000..b6906ff --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/validations/_mongodb.tpl b/deployment/charts/mysql/charts/common/templates/validations/_mongodb.tpl new file mode 100644 index 0000000..f820ec1 --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/validations/_mysql.tpl b/deployment/charts/mysql/charts/common/templates/validations/_mysql.tpl new file mode 100644 index 0000000..74472a0 --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/validations/_postgresql.tpl b/deployment/charts/mysql/charts/common/templates/validations/_postgresql.tpl new file mode 100644 index 0000000..164ec0d --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/validations/_redis.tpl b/deployment/charts/mysql/charts/common/templates/validations/_redis.tpl new file mode 100644 index 0000000..dcccfc1 --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/templates/validations/_validations.tpl b/deployment/charts/mysql/charts/common/templates/validations/_validations.tpl new file mode 100644 index 0000000..9a814cf --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/charts/common/values.yaml b/deployment/charts/mysql/charts/common/values.yaml new file mode 100644 index 0000000..f2df68e --- /dev/null +++ b/deployment/charts/mysql/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/deployment/charts/mysql/templates/NOTES.txt b/deployment/charts/mysql/templates/NOTES.txt new file mode 100644 index 0000000..ecf604c --- /dev/null +++ b/deployment/charts/mysql/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 {{ include "common.names.namespace" . }} -l app.kubernetes.io/instance={{ .Release.Name }} + +Access the pod you want to debug by executing + + kubectl exec --namespace {{ include "common.names.namespace" . }} -ti -- bash + +In order to replicate the container startup scripts execute this command: + + /opt/bitnami/scripts/mysql/entrypoint.sh /opt/bitnami/scripts/mysql/run.sh + +{{- else }} + +Tip: + + Watch the deployment status using the command: kubectl get pods -w --namespace {{ include "common.names.namespace" . }} + +Services: + + echo Primary: {{ include "mysql.primary.fullname" . }}.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }}:{{ .Values.primary.service.ports.mysql }} +{{- if eq .Values.architecture "replication" }} + echo Secondary: {{ include "mysql.secondary.fullname" . }}.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }}:{{ .Values.secondary.service.ports.mysql }} +{{- end }} + +Execute the following to get the administrator credentials: + + echo Username: root + MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace {{ include "common.names.namespace" . }} {{ template "mysql.secretName" . }} -o jsonpath="{.data.mysql-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 "mysql.image" . }} --namespace {{ include "common.names.namespace" . }} --env MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD --command -- bash + + 2. To connect to primary service (read/write): + + mysql -h {{ include "mysql.primary.fullname" . }}.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }} -uroot -p"$MYSQL_ROOT_PASSWORD" + +{{- if eq .Values.architecture "replication" }} + + 3. To connect to secondary service (read-only): + + mysql -h {{ include "mysql.secondary.fullname" . }}.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }} -uroot -p"$MYSQL_ROOT_PASSWORD" +{{- end }} + +{{ if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }} +Note: Since NetworkPolicy is enabled, only pods with label {{ template "common.names.fullname" . }}-client=true" will be able to connect to MySQL. +{{- end }} + +{{- if .Values.metrics.enabled }} + +To access the MySQL Prometheus metrics from outside the cluster execute the following commands: + + kubectl port-forward --namespace {{ include "common.names.namespace" . }} svc/{{ printf "%s-metrics" (include "common.names.fullname" .) }} {{ .Values.metrics.service.port }}:{{ .Values.metrics.service.port }} & + curl http://127.0.0.1:{{ .Values.metrics.service.port }}/metrics + +{{- end }} + +{{ include "mysql.validateValues" . }} +{{ include "mysql.checkRollingTags" . }} +{{- end }} diff --git a/deployment/charts/mysql/templates/_helpers.tpl b/deployment/charts/mysql/templates/_helpers.tpl new file mode 100644 index 0000000..322826f --- /dev/null +++ b/deployment/charts/mysql/templates/_helpers.tpl @@ -0,0 +1,161 @@ +{{/* vim: set filetype=mustache: */}} + +{{- define "mysql.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 "mysql.secondary.fullname" -}} +{{- printf "%s-%s" (include "common.names.fullname" .) .Values.secondary.name | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Return the proper MySQL image name +*/}} +{{- define "mysql.image" -}} +{{- include "common.images.image" (dict "imageRoot" .Values.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper metrics image name +*/}} +{{- define "mysql.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 "mysql.volumePermissions.image" -}} +{{- include "common.images.image" (dict "imageRoot" .Values.volumePermissions.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names +*/}} +{{- define "mysql.imagePullSecrets" -}} +{{- include "common.images.pullSecrets" (dict "images" (list .Values.image .Values.metrics.image .Values.volumePermissions.image) "global" .Values.global) }} +{{- end -}} + +{{/* +Get the initialization scripts ConfigMap name. +*/}} +{{- define "mysql.initdbScriptsCM" -}} +{{- if .Values.initdbScriptsConfigMap -}} + {{- printf "%s" (tpl .Values.initdbScriptsConfigMap $) -}} +{{- else -}} + {{- printf "%s-init-scripts" (include "mysql.primary.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* + Returns the proper service account name depending if an explicit service account name is set + in the values file. If the name is not set it will default to either mysql.fullname if serviceAccount.create + is true or default otherwise. +*/}} +{{- define "mysql.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 MySQL Primary configuration +*/}} +{{- define "mysql.primary.configmapName" -}} +{{- if .Values.primary.existingConfigmap -}} + {{- printf "%s" (tpl .Values.primary.existingConfigmap $) -}} +{{- else -}} + {{- printf "%s" (include "mysql.primary.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a configmap object should be created for MySQL Secondary +*/}} +{{- define "mysql.primary.createConfigmap" -}} +{{- if and .Values.primary.configuration (not .Values.primary.existingConfigmap) }} + {{- true -}} +{{- else -}} +{{- end -}} +{{- end -}} + +{{/* +Return the configmap with the MySQL Primary configuration +*/}} +{{- define "mysql.secondary.configmapName" -}} +{{- if .Values.secondary.existingConfigmap -}} + {{- printf "%s" (tpl .Values.secondary.existingConfigmap $) -}} +{{- else -}} + {{- printf "%s" (include "mysql.secondary.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a configmap object should be created for MySQL Secondary +*/}} +{{- define "mysql.secondary.createConfigmap" -}} +{{- if and (eq .Values.architecture "replication") .Values.secondary.configuration (not .Values.secondary.existingConfigmap) }} + {{- true -}} +{{- else -}} +{{- end -}} +{{- end -}} + +{{/* +Return the secret with MySQL credentials +*/}} +{{- define "mysql.secretName" -}} + {{- if .Values.auth.existingSecret -}} + {{- printf "%s" (tpl .Values.auth.existingSecret $) -}} + {{- else -}} + {{- printf "%s" (include "common.names.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{/* +Return true if a secret object should be created for MySQL +*/}} +{{- define "mysql.createSecret" -}} +{{- if and (not .Values.auth.existingSecret) (not .Values.auth.customPasswordFiles) }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Returns the available value for certain key in an existing secret (if it exists), +otherwise it generates a random value. +*/}} +{{- define "getValueFromSecret" }} + {{- $len := (default 16 .Length) | int -}} + {{- $obj := (lookup "v1" "Secret" .Namespace .Name).data -}} + {{- if $obj }} + {{- index $obj .Key | b64dec -}} + {{- else -}} + {{- randAlphaNum $len -}} + {{- end -}} +{{- end }} + +{{/* Check if there are rolling tags in the images */}} +{{- define "mysql.checkRollingTags" -}} +{{- include "common.warnings.rollingTag" .Values.image }} +{{- include "common.warnings.rollingTag" .Values.metrics.image }} +{{- include "common.warnings.rollingTag" .Values.volumePermissions.image }} +{{- end -}} + +{{/* +Compile all warnings into a single message, and call fail. +*/}} +{{- define "mysql.validateValues" -}} +{{- $messages := list -}} +{{- $messages := without $messages "" -}} +{{- $message := join "\n" $messages -}} + +{{- if $message -}} +{{- printf "\nVALUES VALIDATION:\n%s" $message | fail -}} +{{- end -}} +{{- end -}} diff --git a/deployment/charts/mysql/templates/extra-list.yaml b/deployment/charts/mysql/templates/extra-list.yaml new file mode 100644 index 0000000..9ac65f9 --- /dev/null +++ b/deployment/charts/mysql/templates/extra-list.yaml @@ -0,0 +1,4 @@ +{{- range .Values.extraDeploy }} +--- +{{ include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- end }} diff --git a/deployment/charts/mysql/templates/metrics-svc.yaml b/deployment/charts/mysql/templates/metrics-svc.yaml new file mode 100644 index 0000000..4d3339b --- /dev/null +++ b/deployment/charts/mysql/templates/metrics-svc.yaml @@ -0,0 +1,29 @@ +{{- if .Values.metrics.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ printf "%s-metrics" (include "common.names.fullname" .) }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + app.kubernetes.io/component: metrics + {{- if or .Values.metrics.service.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.metrics.service.annotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.service.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: {{ .Values.metrics.service.type }} + ports: + - port: {{ .Values.metrics.service.port }} + targetPort: metrics + protocol: TCP + name: metrics + selector: {{- include "common.labels.matchLabels" $ | nindent 4 }} +{{- end }} diff --git a/deployment/charts/mysql/templates/networkpolicy.yaml b/deployment/charts/mysql/templates/networkpolicy.yaml new file mode 100644 index 0000000..6b62bb5 --- /dev/null +++ b/deployment/charts/mysql/templates/networkpolicy.yaml @@ -0,0 +1,40 @@ +{{- if .Values.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: {{ template "common.capabilities.networkPolicy.apiVersion" . }} +metadata: + name: {{ template "common.names.fullname" . }} + namespace: {{ include "common.names.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.matchLabels" . | nindent 6 }} + ingress: + # Allow inbound connections + - ports: + - port: {{ .Values.primary.service.ports.mysql }} + {{- if not .Values.networkPolicy.allowExternal }} + from: + - podSelector: + matchLabels: + {{ template "common.names.fullname" . }}-client: "true" + {{- if .Values.networkPolicy.explicitNamespacesSelector }} + namespaceSelector: +{{ toYaml .Values.networkPolicy.explicitNamespacesSelector | indent 12 }} + {{- end }} + - podSelector: + matchLabels: + {{- include "common.labels.matchLabels" . | nindent 14 }} + {{- end }} + {{- if .Values.metrics.enabled }} + # Allow prometheus scrapes + - ports: + - port: 9104 + {{- end }} +{{- end }} diff --git a/deployment/charts/mysql/templates/primary/configmap.yaml b/deployment/charts/mysql/templates/primary/configmap.yaml new file mode 100644 index 0000000..82d0774 --- /dev/null +++ b/deployment/charts/mysql/templates/primary/configmap.yaml @@ -0,0 +1,18 @@ +{{- if (include "mysql.primary.createConfigmap" .) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "mysql.primary.fullname" . }} + namespace: {{ include "common.names.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: |- + {{- include "common.tplvalues.render" ( dict "value" .Values.primary.configuration "context" $ ) | nindent 4 }} +{{- end -}} diff --git a/deployment/charts/mysql/templates/primary/initialization-configmap.yaml b/deployment/charts/mysql/templates/primary/initialization-configmap.yaml new file mode 100644 index 0000000..a34f80d --- /dev/null +++ b/deployment/charts/mysql/templates/primary/initialization-configmap.yaml @@ -0,0 +1,17 @@ +{{- if and .Values.initdbScripts (not .Values.initdbScriptsConfigMap) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-init-scripts" (include "mysql.primary.fullname" .) }} + namespace: {{ include "common.names.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: +{{- include "common.tplvalues.render" (dict "value" .Values.initdbScripts "context" .) | nindent 2 }} +{{- end }} diff --git a/deployment/charts/mysql/templates/primary/pdb.yaml b/deployment/charts/mysql/templates/primary/pdb.yaml new file mode 100644 index 0000000..ca22a0e --- /dev/null +++ b/deployment/charts/mysql/templates/primary/pdb.yaml @@ -0,0 +1,25 @@ +{{- if .Values.primary.pdb.create }} +apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ include "mysql.primary.fullname" . }} + namespace: {{ include "common.names.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/deployment/charts/mysql/templates/primary/statefulset.yaml b/deployment/charts/mysql/templates/primary/statefulset.yaml new file mode 100644 index 0000000..7be0254 --- /dev/null +++ b/deployment/charts/mysql/templates/primary/statefulset.yaml @@ -0,0 +1,382 @@ +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ include "mysql.primary.fullname" . }} + namespace: {{ include "common.names.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 + podManagementPolicy: {{ .Values.primary.podManagementPolicy | quote }} + selector: + matchLabels: {{ include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: primary + serviceName: {{ include "mysql.primary.fullname" . }} + {{- if .Values.primary.updateStrategy }} + updateStrategy: {{- toYaml .Values.primary.updateStrategy | nindent 4 }} + {{- end }} + template: + metadata: + annotations: + {{- if (include "mysql.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 }} + spec: + serviceAccountName: {{ template "mysql.serviceAccountName" . }} + {{- include "mysql.imagePullSecrets" . | nindent 6 }} + {{- if .Values.primary.hostAliases }} + hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.primary.hostAliases "context" $) | nindent 8 }} + {{- end }} + {{- 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 "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.primary.podAntiAffinityPreset "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.priorityClassName }} + priorityClassName: {{ .Values.primary.priorityClassName | quote }} + {{- end }} + {{- if .Values.primary.runtimeClassName }} + runtimeClassName: {{ .Values.primary.runtimeClassName | quote }} + {{- end }} + {{- if .Values.primary.schedulerName }} + schedulerName: {{ .Values.primary.schedulerName | quote }} + {{- end }} + {{- if .Values.primary.topologySpreadConstraints }} + topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.primary.topologySpreadConstraints "context" .) | nindent 8 }} + {{- end }} + {{- if .Values.primary.podSecurityContext.enabled }} + securityContext: {{- omit .Values.primary.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.primary.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.primary.terminationGracePeriodSeconds }} + {{- end }} + initContainers: + {{- if and .Values.primary.podSecurityContext.enabled .Values.volumePermissions.enabled .Values.primary.persistence.enabled }} + - name: volume-permissions + image: {{ include "mysql.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + command: + - /bin/bash + - -ec + - | + mkdir -p "/bitnami/mysql" + chown "{{ .Values.primary.containerSecurityContext.runAsUser }}:{{ .Values.primary.podSecurityContext.fsGroup }}" "/bitnami/mysql" + find "/bitnami/mysql" -mindepth 1 -maxdepth 1 -not -name ".snapshot" -not -name "lost+found" | xargs -r chown -R "{{ .Values.primary.containerSecurityContext.runAsUser }}:{{ .Values.primary.podSecurityContext.fsGroup }}" + securityContext: + runAsUser: 0 + {{- if .Values.volumePermissions.resources }} + resources: {{- toYaml .Values.volumePermissions.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: /bitnami/mysql + {{- if .Values.primary.persistence.subPath }} + subPath: {{ .Values.primary.persistence.subPath }} + {{- end }} + {{- end }} + {{- if .Values.primary.initContainers }} + {{- include "common.tplvalues.render" (dict "value" .Values.primary.initContainers "context" $) | nindent 8 }} + {{- end }} + containers: + - name: mysql + image: {{ include "mysql.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: MYSQL_ROOT_PASSWORD_FILE + value: {{ default "/opt/bitnami/mysql/secrets/mysql-root-password" .Values.auth.customPasswordFiles.root }} + {{- else }} + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mysql.secretName" . }} + key: mysql-root-password + {{- end }} + {{- if not (empty .Values.auth.username) }} + - name: MYSQL_USER + value: {{ .Values.auth.username | quote }} + {{- if .Values.auth.usePasswordFiles }} + - name: MYSQL_PASSWORD_FILE + value: {{ default "/opt/bitnami/mysql/secrets/mysql-password" .Values.auth.customPasswordFiles.user }} + {{- else }} + - name: MYSQL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mysql.secretName" . }} + key: mysql-password + {{- end }} + {{- end }} + {{- if and .Values.auth.createDatabase .Values.auth.database }} + - name: MYSQL_DATABASE + value: {{ .Values.auth.database | quote }} + {{- end }} + {{- if eq .Values.architecture "replication" }} + - name: MYSQL_REPLICATION_MODE + value: "master" + - name: MYSQL_REPLICATION_USER + value: {{ .Values.auth.replicationUser | quote }} + {{- if .Values.auth.usePasswordFiles }} + - name: MYSQL_REPLICATION_PASSWORD_FILE + value: {{ default "/opt/bitnami/mysql/secrets/mysql-replication-password" .Values.auth.customPasswordFiles.replicator }} + {{- else }} + - name: MYSQL_REPLICATION_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mysql.secretName" . }} + key: mysql-replication-password + {{- end }} + {{- end }} + {{- if .Values.primary.extraFlags }} + - name: MYSQL_EXTRA_FLAGS + value: "{{ .Values.primary.extraFlags }}" + {{- end }} + {{- if .Values.primary.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.primary.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + envFrom: + {{- if .Values.primary.extraEnvVarsCM }} + - configMapRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.primary.extraEnvVarsCM "context" $) }} + {{- end }} + {{- if .Values.primary.extraEnvVarsSecret }} + - secretRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.primary.extraEnvVarsSecret "context" $) }} + {{- end }} + ports: + - name: mysql + containerPort: 3306 + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.primary.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.primary.customLivenessProbe "context" $) | nindent 12 }} + {{- else if .Values.primary.livenessProbe.enabled }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.primary.livenessProbe "enabled") "context" $) | nindent 12 }} + exec: + command: + - /bin/bash + - -ec + - | + password_aux="${MYSQL_ROOT_PASSWORD:-}" + if [[ -f "${MYSQL_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MYSQL_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: {{- include "common.tplvalues.render" (dict "value" (omit .Values.primary.readinessProbe "enabled") "context" $) | nindent 12 }} + exec: + command: + - /bin/bash + - -ec + - | + password_aux="${MYSQL_ROOT_PASSWORD:-}" + if [[ -f "${MYSQL_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MYSQL_ROOT_PASSWORD_FILE") + fi + mysqladmin status -uroot -p"${password_aux}" + {{- end }} + {{- if .Values.primary.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.primary.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.primary.startupProbe.enabled }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.primary.startupProbe "enabled") "context" $) | nindent 12 }} + exec: + command: + - /bin/bash + - -ec + - | + password_aux="${MYSQL_ROOT_PASSWORD:-}" + if [[ -f "${MYSQL_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MYSQL_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/mysql + {{- 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/mysql/conf/my.cnf + subPath: my.cnf + {{- end }} + {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} + - name: mysql-credentials + mountPath: /opt/bitnami/mysql/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 "mysql.metrics.image" . }} + imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} + env: + {{- if .Values.auth.usePasswordFiles }} + - name: MYSQL_ROOT_PASSWORD_FILE + value: {{ default "/opt/bitnami/mysqld-exporter/secrets/mysql-root-password" .Values.auth.customPasswordFiles.root }} + {{- else }} + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "mysql.secretName" . }} + key: mysql-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="${MYSQL_ROOT_PASSWORD:-}" + if [[ -f "${MYSQL_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MYSQL_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 }} + {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} + volumeMounts: + - name: mysql-credentials + mountPath: /opt/bitnami/mysqld-exporter/secrets/ + {{- 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 "mysql.primary.configmapName" . }} + {{- end }} + {{- if or .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + configMap: + name: {{ include "mysql.initdbScriptsCM" . }} + {{- end }} + {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} + - name: mysql-credentials + secret: + secretName: {{ include "mysql.secretName" . }} + items: + - key: mysql-root-password + path: mysql-root-password + - key: mysql-password + path: mysql-password + {{- if eq .Values.architecture "replication" }} + - key: mysql-replication-password + path: mysql-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.commonLabels }} + {{- include "common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 10 }} + {{- end }} + annotations: + {{- if .Values.primary.persistence.annotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.primary.persistence.annotations "context" $) | nindent 10 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.commonAnnotations "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) | nindent 8 }} + {{- if .Values.primary.persistence.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.primary.persistence.selector "context" $) | nindent 10 }} + {{- end -}} + {{- end }} diff --git a/deployment/charts/mysql/templates/primary/svc-headless.yaml b/deployment/charts/mysql/templates/primary/svc-headless.yaml new file mode 100644 index 0000000..c430d94 --- /dev/null +++ b/deployment/charts/mysql/templates/primary/svc-headless.yaml @@ -0,0 +1,29 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "mysql.primary.fullname" . }}-headless + namespace: {{ include "common.names.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 or .Values.primary.service.headless.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.primary.service.headless.annotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.primary.service.headless.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: ClusterIP + clusterIP: None + publishNotReadyAddresses: true + ports: + - name: mysql + port: {{ .Values.primary.service.ports.mysql }} + targetPort: mysql + selector: {{ include "common.labels.matchLabels" . | nindent 4 }} + app.kubernetes.io/component: primary diff --git a/deployment/charts/mysql/templates/primary/svc.yaml b/deployment/charts/mysql/templates/primary/svc.yaml new file mode 100644 index 0000000..b61d453 --- /dev/null +++ b/deployment/charts/mysql/templates/primary/svc.yaml @@ -0,0 +1,52 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "mysql.primary.fullname" . }} + namespace: {{ include "common.names.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 }} +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 .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 }} + {{- if 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") (not (empty .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 }} + ports: + - name: mysql + port: {{ .Values.primary.service.ports.mysql }} + protocol: TCP + targetPort: mysql + {{- if (and (or (eq .Values.primary.service.type "NodePort") (eq .Values.primary.service.type "LoadBalancer")) .Values.primary.service.nodePorts.mysql) }} + nodePort: {{ .Values.primary.service.nodePorts.mysql }} + {{- else if eq .Values.primary.service.type "ClusterIP" }} + nodePort: null + {{- 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/deployment/charts/mysql/templates/prometheusrule.yaml b/deployment/charts/mysql/templates/prometheusrule.yaml new file mode 100644 index 0000000..64fa44f --- /dev/null +++ b/deployment/charts/mysql/templates/prometheusrule.yaml @@ -0,0 +1,22 @@ +{{- if and .Values.metrics.enabled .Values.metrics.prometheusRule.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ include "common.names.fullname" . }} + namespace: {{ default .Release.Namespace .Values.metrics.prometheusRule.namespace }} + 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/deployment/charts/mysql/templates/role.yaml b/deployment/charts/mysql/templates/role.yaml new file mode 100644 index 0000000..1ccc00a --- /dev/null +++ b/deployment/charts/mysql/templates/role.yaml @@ -0,0 +1,24 @@ +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +kind: Role +metadata: + name: {{ include "common.names.fullname" . }} + namespace: {{ include "common.names.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 + {{- if .Values.rbac.rules }} + {{- include "common.tplvalues.render" ( dict "value" .Values.rbac.rules "context" $ ) | nindent 2 }} + {{- end }} +{{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/rolebinding.yaml b/deployment/charts/mysql/templates/rolebinding.yaml similarity index 53% rename from deployment/deployment/nginx-ingress-controller/templates/rolebinding.yaml rename to deployment/charts/mysql/templates/rolebinding.yaml index 3812828..9b05208 100644 --- a/deployment/deployment/nginx-ingress-controller/templates/rolebinding.yaml +++ b/deployment/charts/mysql/templates/rolebinding.yaml @@ -1,22 +1,21 @@ -{{- if .Values.rbac.create -}} -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +{{- if and .Values.serviceAccount.create .Values.rbac.create }} kind: RoleBinding +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ .Release.Namespace | quote }} + name: {{ include "common.names.fullname" . }} + namespace: {{ include "common.names.namespace" . | quote }} labels: {{- include "common.labels.standard" . | nindent 4 }} {{- if .Values.commonLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- 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 "mysql.serviceAccountName" . }} roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: {{ template "common.names.fullname" . }} -subjects: - - kind: ServiceAccount - name: {{ include "nginx-ingress-controller.serviceAccountName" . }} - namespace: {{ .Release.Namespace | quote }} -{{- end -}} + name: {{ include "common.names.fullname" . -}} +{{- end }} diff --git a/deployment/charts/mysql/templates/secondary/configmap.yaml b/deployment/charts/mysql/templates/secondary/configmap.yaml new file mode 100644 index 0000000..c94724f --- /dev/null +++ b/deployment/charts/mysql/templates/secondary/configmap.yaml @@ -0,0 +1,18 @@ +{{- if (include "mysql.secondary.createConfigmap" .) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "mysql.secondary.fullname" . }} + namespace: {{ include "common.names.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: |- + {{- include "common.tplvalues.render" ( dict "value" .Values.secondary.configuration "context" $ ) | nindent 4 }} +{{- end -}} diff --git a/deployment/charts/mysql/templates/secondary/pdb.yaml b/deployment/charts/mysql/templates/secondary/pdb.yaml new file mode 100644 index 0000000..b4a5aee --- /dev/null +++ b/deployment/charts/mysql/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 "mysql.secondary.fullname" . }} + namespace: {{ include "common.names.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/deployment/charts/mysql/templates/secondary/statefulset.yaml b/deployment/charts/mysql/templates/secondary/statefulset.yaml new file mode 100644 index 0000000..3b731b5 --- /dev/null +++ b/deployment/charts/mysql/templates/secondary/statefulset.yaml @@ -0,0 +1,363 @@ +{{- if eq .Values.architecture "replication" }} +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ include "mysql.secondary.fullname" . }} + namespace: {{ include "common.names.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 }} + podManagementPolicy: {{ .Values.secondary.podManagementPolicy | quote }} + selector: + matchLabels: {{ include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: secondary + serviceName: {{ include "mysql.secondary.fullname" . }} + {{- if .Values.secondary.updateStrategy }} + updateStrategy: {{- toYaml .Values.secondary.updateStrategy | nindent 4 }} + {{- end }} + template: + metadata: + annotations: + {{- if (include "mysql.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 }} + spec: + serviceAccountName: {{ include "mysql.serviceAccountName" . }} + {{- include "mysql.imagePullSecrets" . | nindent 6 }} + {{- 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 "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.secondary.podAntiAffinityPreset "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.priorityClassName }} + priorityClassName: {{ .Values.secondary.priorityClassName | quote }} + {{- end }} + {{- if .Values.secondary.runtimeClassName }} + runtimeClassName: {{ .Values.secondary.runtimeClassName | quote }} + {{- end }} + {{- if .Values.secondary.schedulerName }} + schedulerName: {{ .Values.secondary.schedulerName | quote }} + {{- end }} + {{- if .Values.secondary.topologySpreadConstraints }} + topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.topologySpreadConstraints "context" .) | nindent 8 }} + {{- end }} + {{- if .Values.secondary.podSecurityContext.enabled }} + securityContext: {{- omit .Values.secondary.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.secondary.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.secondary.terminationGracePeriodSeconds }} + {{- end }} + initContainers: + {{- if and .Values.secondary.podSecurityContext.enabled .Values.volumePermissions.enabled .Values.secondary.persistence.enabled }} + - name: volume-permissions + image: {{ include "mysql.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + command: + - /bin/bash + - -ec + - | + mkdir -p "/bitnami/mysql" + chown "{{ .Values.secondary.containerSecurityContext.runAsUser }}:{{ .Values.secondary.podSecurityContext.fsGroup }}" "/bitnami/mysql" + find "/bitnami/mysql" -mindepth 1 -maxdepth 1 -not -name ".snapshot" -not -name "lost+found" | xargs -r chown -R "{{ .Values.secondary.containerSecurityContext.runAsUser }}:{{ .Values.secondary.podSecurityContext.fsGroup }}" + securityContext: + runAsUser: 0 + {{- if .Values.volumePermissions.resources }} + resources: {{- toYaml .Values.volumePermissions.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: /bitnami/mysql + {{- if .Values.secondary.persistence.subPath }} + subPath: {{ .Values.secondary.persistence.subPath }} + {{- end }} + {{- end }} + {{- if .Values.secondary.initContainers }} + {{- include "common.tplvalues.render" (dict "value" .Values.secondary.initContainers "context" $) | nindent 8 }} + {{- end }} + containers: + - name: mysql + image: {{ include "mysql.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: MYSQL_REPLICATION_MODE + value: "slave" + - name: MYSQL_MASTER_HOST + value: {{ include "mysql.primary.fullname" . }} + - name: MYSQL_MASTER_PORT_NUMBER + value: {{ .Values.primary.service.ports.mysql | quote }} + - name: MYSQL_MASTER_ROOT_USER + value: "root" + - name: MYSQL_REPLICATION_USER + value: {{ .Values.auth.replicationUser | quote }} + {{- if .Values.auth.usePasswordFiles }} + - name: MYSQL_MASTER_ROOT_PASSWORD_FILE + value: {{ default "/opt/bitnami/mysql/secrets/mysql-root-password" .Values.auth.customPasswordFiles.root }} + - name: MYSQL_REPLICATION_PASSWORD_FILE + value: {{ default "/opt/bitnami/mysql/secrets/mysql-replication-password" .Values.auth.customPasswordFiles.replicator }} + {{- else }} + - name: MYSQL_MASTER_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mysql.secretName" . }} + key: mysql-root-password + - name: MYSQL_REPLICATION_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mysql.secretName" . }} + key: mysql-replication-password + {{- end }} + {{- if .Values.secondary.extraFlags }} + - name: MYSQL_EXTRA_FLAGS + value: "{{ .Values.secondary.extraFlags }}" + {{- end }} + {{- if .Values.secondary.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.secondary.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + envFrom: + {{- if .Values.secondary.extraEnvVarsCM }} + - configMapRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.secondary.extraEnvVarsCM "context" $) }} + {{- end }} + {{- if .Values.secondary.extraEnvVarsSecret }} + - secretRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.secondary.extraEnvVarsSecret "context" $) }} + {{- end }} + ports: + - name: mysql + containerPort: 3306 + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.secondary.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.customLivenessProbe "context" $) | nindent 12 }} + {{- else if .Values.secondary.livenessProbe.enabled }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.secondary.livenessProbe "enabled") "context" $) | nindent 12 }} + exec: + command: + - /bin/bash + - -ec + - | + password_aux="${MYSQL_MASTER_ROOT_PASSWORD:-}" + if [[ -f "${MYSQL_MASTER_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MYSQL_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: {{- include "common.tplvalues.render" (dict "value" (omit .Values.secondary.readinessProbe "enabled") "context" $) | nindent 12 }} + exec: + command: + - /bin/bash + - -ec + - | + password_aux="${MYSQL_MASTER_ROOT_PASSWORD:-}" + if [[ -f "${MYSQL_MASTER_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MYSQL_MASTER_ROOT_PASSWORD_FILE") + fi + mysqladmin status -uroot -p"${password_aux}" + {{- end }} + {{- if .Values.secondary.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.secondary.startupProbe.enabled }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.secondary.startupProbe "enabled") "context" $) | nindent 12 }} + exec: + command: + - /bin/bash + - -ec + - | + password_aux="${MYSQL_MASTER_ROOT_PASSWORD:-}" + if [[ -f "${MYSQL_MASTER_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MYSQL_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/mysql + {{- if .Values.secondary.persistence.subPath }} + subPath: {{ .Values.secondary.persistence.subPath }} + {{- end }} + {{- if or .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + mountPath: /docker-entrypoint-initdb.d + {{- end }} + {{- if or .Values.secondary.configuration .Values.secondary.existingConfigmap }} + - name: config + mountPath: /opt/bitnami/mysql/conf/my.cnf + subPath: my.cnf + {{- end }} + {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} + - name: mysql-credentials + mountPath: /opt/bitnami/mysql/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 "mysql.metrics.image" . }} + imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} + env: + {{- if .Values.auth.usePasswordFiles }} + - name: MYSQL_ROOT_PASSWORD_FILE + value: {{ default "/opt/bitnami/mysqld-exporter/secrets/mysql-root-password" .Values.auth.customPasswordFiles.root }} + {{- else }} + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mysql.secretName" . }} + key: mysql-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="${MYSQL_ROOT_PASSWORD:-}" + if [[ -f "${MYSQL_ROOT_PASSWORD_FILE:-}" ]]; then + password_aux=$(cat "$MYSQL_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 }} + {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} + volumeMounts: + - name: mysql-credentials + mountPath: /opt/bitnami/mysqld-exporter/secrets/ + {{- end }} + {{- end }} + {{- if .Values.secondary.sidecars }} + {{- include "common.tplvalues.render" (dict "value" .Values.secondary.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + {{- if or .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + configMap: + name: {{ include "mysql.initdbScriptsCM" . }} + {{- end }} + {{- if or .Values.secondary.configuration .Values.secondary.existingConfigmap }} + - name: config + configMap: + name: {{ include "mysql.secondary.configmapName" . }} + {{- end }} + {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} + - name: mysql-credentials + secret: + secretName: {{ template "mysql.secretName" . }} + items: + - key: mysql-root-password + path: mysql-root-password + - key: mysql-replication-password + path: mysql-replication-password + {{- end }} + {{- if .Values.secondary.extraVolumes }} + {{- include "common.tplvalues.render" (dict "value" .Values.secondary.extraVolumes "context" $) | nindent 8 }} + {{- end }} + {{- if and .Values.secondary.persistence.enabled .Values.secondary.persistence.existingClaim }} + - name: data + persistentVolumeClaim: + claimName: {{ tpl .Values.secondary.persistence.existingClaim . }} + {{- else 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.commonLabels }} + {{- include "common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 10 }} + {{- end }} + annotations: + {{- if .Values.secondary.persistence.annotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.secondary.persistence.annotations "context" $) | nindent 10 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.commonAnnotations "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) | nindent 8 }} + {{- 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/deployment/charts/mysql/templates/secondary/svc-headless.yaml b/deployment/charts/mysql/templates/secondary/svc-headless.yaml new file mode 100644 index 0000000..44cfa4a --- /dev/null +++ b/deployment/charts/mysql/templates/secondary/svc-headless.yaml @@ -0,0 +1,31 @@ +{{- if eq .Values.architecture "replication" }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "mysql.secondary.fullname" . }}-headless + namespace: {{ include "common.names.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 or .Values.secondary.service.headless.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.secondary.service.headless.annotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.secondary.service.headless.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: ClusterIP + clusterIP: None + publishNotReadyAddresses: true + ports: + - name: mysql + port: {{ .Values.secondary.service.ports.mysql }} + targetPort: mysql + selector: {{ include "common.labels.matchLabels" . | nindent 4 }} + app.kubernetes.io/component: secondary +{{- end }} diff --git a/deployment/charts/mysql/templates/secondary/svc.yaml b/deployment/charts/mysql/templates/secondary/svc.yaml new file mode 100644 index 0000000..e6e662c --- /dev/null +++ b/deployment/charts/mysql/templates/secondary/svc.yaml @@ -0,0 +1,54 @@ +{{- if eq .Values.architecture "replication" }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "mysql.secondary.fullname" . }} + namespace: {{ include "common.names.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 }} +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 .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 }} + {{- if 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") (not (empty .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 }} + ports: + - name: mysql + port: {{ .Values.secondary.service.ports.mysql }} + protocol: TCP + targetPort: mysql + {{- if (and (or (eq .Values.secondary.service.type "NodePort") (eq .Values.secondary.service.type "LoadBalancer")) .Values.secondary.service.nodePorts.mysql) }} + nodePort: {{ .Values.secondary.service.nodePorts.mysql }} + {{- else if eq .Values.secondary.service.type "ClusterIP" }} + nodePort: null + {{- 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/deployment/charts/mysql/templates/secrets.yaml b/deployment/charts/mysql/templates/secrets.yaml new file mode 100644 index 0000000..6da5327 --- /dev/null +++ b/deployment/charts/mysql/templates/secrets.yaml @@ -0,0 +1,21 @@ +{{- if eq (include "mysql.createSecret" .) "true" }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "common.names.fullname" . }} + namespace: {{ include "common.names.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: + mysql-root-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "mysql-root-password" "length" 10 "providedValues" (list "auth.rootPassword") "context" $) }} + mysql-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "mysql-password" "length" 10 "providedValues" (list "auth.password") "context" $) }} + {{- if eq .Values.architecture "replication" }} + mysql-replication-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "mysql-replication-password" "length" 10 "providedValues" (list "auth.replicationPassword") "context" $) }} + {{- end }} +{{- end }} diff --git a/deployment/charts/mysql/templates/serviceaccount.yaml b/deployment/charts/mysql/templates/serviceaccount.yaml new file mode 100644 index 0000000..5044961 --- /dev/null +++ b/deployment/charts/mysql/templates/serviceaccount.yaml @@ -0,0 +1,23 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "mysql.serviceAccountName" . }} + namespace: {{ include "common.names.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.commonAnnotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.serviceAccount.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.serviceAccount.annotations "context" $ ) | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} +{{- if (not .Values.auth.customPasswordFiles) }} +secrets: + - name: {{ template "mysql.secretName" . }} +{{- end }} +{{- end }} diff --git a/deployment/charts/mysql/templates/servicemonitor.yaml b/deployment/charts/mysql/templates/servicemonitor.yaml new file mode 100644 index 0000000..47a9dad --- /dev/null +++ b/deployment/charts/mysql/templates/servicemonitor.yaml @@ -0,0 +1,49 @@ +{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "common.names.fullname" . }} + namespace: {{ default (include "common.names.namespace" .) .Values.metrics.serviceMonitor.namespace }} + labels: {{- include "common.labels.standard" . | nindent 4 }} + {{- if .Values.metrics.serviceMonitor.labels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.labels "context" $ ) | nindent 4 }} + {{- end }} + {{- 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.metrics.serviceMonitor.annotations }} + {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.annotations "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: + - {{ include "common.names.namespace" . | quote }} + selector: + matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: metrics + {{- if .Values.metrics.serviceMonitor.selector }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.serviceMonitor.selector "context" $) | nindent 6 }} + {{- end }} +{{- end }} diff --git a/deployment/charts/mysql/values.schema.json b/deployment/charts/mysql/values.schema.json new file mode 100644 index 0000000..df59156 --- /dev/null +++ b/deployment/charts/mysql/values.schema.json @@ -0,0 +1,195 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "architecture": { + "type": "string", + "title": "MySQL architecture", + "form": true, + "description": "Allowed values: `standalone` or `replication`", + "enum": ["standalone", "replication"] + }, + "auth": { + "type": "object", + "title": "Authentication configuration", + "form": true, + "required": ["username", "password"], + "if": { + "properties": { + "createDatabase": { "enum": [ true ] } + } + }, + "then": { + "properties": { + "database": { + "pattern": "[a-zA-Z0-9]{1,64}" + } + } + }, + "properties": { + "rootPassword": { + "type": "string", + "title": "MySQL root password", + "description": "Defaults to a random 10-character alphanumeric string if not set" + }, + "database": { + "type": "string", + "title": "MySQL custom database name", + "maxLength": 64 + }, + "username": { + "type": "string", + "title": "MySQL custom username" + }, + "password": { + "type": "string", + "title": "MySQL custom password" + }, + "replicationUser": { + "type": "string", + "title": "MySQL replication username" + }, + "replicationPassword": { + "type": "string", + "title": "MySQL replication password" + }, + "createDatabase": { + "type": "boolean", + "title": "MySQL create custom database" + } + } + }, + "primary": { + "type": "object", + "title": "Primary database configuration", + "form": true, + "properties": { + "podSecurityContext": { + "type": "object", + "title": "MySQL primary Pod security context", + "properties": { + "enabled": { + "type": "boolean", + "default": false + }, + "fsGroup": { + "type": "integer", + "default": 1001, + "hidden": { + "value": false, + "path": "primary/podSecurityContext/enabled" + } + } + } + }, + "containerSecurityContext": { + "type": "object", + "title": "MySQL primary container security context", + "properties": { + "enabled": { + "type": "boolean", + "default": false + }, + "runAsUser": { + "type": "integer", + "default": 1001, + "hidden": { + "value": false, + "path": "primary/containerSecurityContext/enabled" + } + } + } + }, + "persistence": { + "type": "object", + "title": "Enable persistence using Persistent Volume Claims", + "properties": { + "enabled": { + "type": "boolean", + "default": true, + "title": "If true, use a Persistent Volume Claim, If false, use emptyDir" + }, + "size": { + "type": "string", + "title": "Persistent Volume Size", + "form": true, + "render": "slider", + "sliderMin": 1, + "sliderUnit": "Gi", + "hidden": { + "value": false, + "path": "primary/persistence/enabled" + } + } + } + } + } + }, + "secondary": { + "type": "object", + "title": "Secondary database configuration", + "form": true, + "properties": { + "podSecurityContext": { + "type": "object", + "title": "MySQL secondary Pod security context", + "properties": { + "enabled": { + "type": "boolean", + "default": false + }, + "fsGroup": { + "type": "integer", + "default": 1001, + "hidden": { + "value": false, + "path": "secondary/podSecurityContext/enabled" + } + } + } + }, + "containerSecurityContext": { + "type": "object", + "title": "MySQL secondary container security context", + "properties": { + "enabled": { + "type": "boolean", + "default": false + }, + "runAsUser": { + "type": "integer", + "default": 1001, + "hidden": { + "value": false, + "path": "secondary/containerSecurityContext/enabled" + } + } + } + }, + "persistence": { + "type": "object", + "title": "Enable persistence using Persistent Volume Claims", + "properties": { + "enabled": { + "type": "boolean", + "default": true, + "title": "If true, use a Persistent Volume Claim, If false, use emptyDir" + }, + "size": { + "type": "string", + "title": "Persistent Volume Size", + "form": true, + "render": "slider", + "sliderMin": 1, + "sliderUnit": "Gi", + "hidden": { + "value": false, + "path": "secondary/persistence/enabled" + } + } + } + } + } + } + } +} diff --git a/deployment/charts/mysql/values.yaml b/deployment/charts/mysql/values.yaml new file mode 100644 index 0000000..d010209 --- /dev/null +++ b/deployment/charts/mysql/values.yaml @@ -0,0 +1,1208 @@ +## @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 StorageClass for Persistent Volume(s) +## +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 common.names.fullname template (will maintain the release name) +## +nameOverride: "" +## @param fullnameOverride String to fully override common.names.fullname template +## +fullnameOverride: "" +## @param namespaceOverride String to fully override common.names.namespace +## +namespaceOverride: "" +## @param clusterDomain Cluster domain +## +clusterDomain: cluster.local +## @param commonAnnotations Common annotations to add to all MySQL resources (sub-charts are not considered). Evaluated as a template +## +commonAnnotations: {} +## @param commonLabels Common labels to add to all MySQL resources (sub-charts are not considered). Evaluated as a template +## +commonLabels: {} +## @param extraDeploy Array with extra yaml to deploy with the chart. 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 MySQL common parameters + +## Bitnami MySQL image +## ref: https://hub.docker.com/r/bitnami/mysql/tags/ +## @param image.registry MySQL image registry +## @param image.repository MySQL image repository +## @param image.tag MySQL image tag (immutable tags are recommended) +## @param image.digest MySQL image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag +## @param image.pullPolicy MySQL 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/mysql + tag: 8.0.31-debian-11-r30 + 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 MySQL architecture (`standalone` or `replication`) +## +architecture: standalone +## MySQL 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/mysql#setting-the-root-password-on-first-run + ## + rootPassword: "" + ## @param auth.createDatabase Wheter to create the .Values.auth.database or not + ## ref: https://github.com/bitnami/containers/tree/main/bitnami/mysql#creating-a-database-on-first-run + ## + createDatabase: true + ## @param auth.database Name for a custom database to create + ## ref: https://github.com/bitnami/containers/tree/main/bitnami/mysql#creating-a-database-on-first-run + ## + database: "my_database" + ## @param auth.username Name for a custom user to create + ## ref: https://github.com/bitnami/containers/tree/main/bitnami/mysql#creating-a-database-user-on-first-run + ## + username: "" + ## @param auth.password Password for the new user. Ignored if existing secret is provided + ## + password: "" + ## @param auth.replicationUser MySQL replication user + ## ref: https://github.com/bitnami/containers/tree/main/bitnami/mysql#setting-up-a-replication-cluster + ## + replicationUser: replicator + ## @param auth.replicationPassword MySQL replication user password. Ignored if existing secret is provided + ## + replicationPassword: "" + ## @param auth.existingSecret Use existing secret for password details. The secret has to contain the keys `mysql-root-password`, `mysql-replication-password` and `mysql-password` + ## NOTE: When it's set the auth.rootPassword, auth.password, auth.replicationPassword are ignored. + ## + existingSecret: "" + ## @param auth.usePasswordFiles Mount credentials as files instead of using an environment variable + ## + 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/mysql-root + ## user: /vault/secrets/mysql-user + ## replicator: /vault/secrets/mysql-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 MySQL 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 MySQL Primary container(s) (useful when using custom images) + ## + command: [] + ## @param primary.args Override default container args on MySQL Primary container(s) (useful when using custom images) + ## + args: [] + ## @param primary.lifecycleHooks for the MySQL Primary container(s) to automate configuration before or after startup + ## + lifecycleHooks: {} + ## @param primary.hostAliases Deployment pod host aliases + ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ + ## + hostAliases: [] + ## @param primary.configuration [string] Configure MySQL Primary with a custom my.cnf file + ## ref: https://mysql.com/kb/en/mysql/configuring-mysql-with-mycnf/#example-of-configuration-file + ## + configuration: |- + [mysqld] + default_authentication_plugin=mysql_native_password + skip-name-resolve + explicit_defaults_for_timestamp + basedir=/opt/bitnami/mysql + plugin_dir=/opt/bitnami/mysql/lib/plugin + port=3306 + socket=/opt/bitnami/mysql/tmp/mysql.sock + datadir=/bitnami/mysql/data + tmpdir=/opt/bitnami/mysql/tmp + max_allowed_packet=16M + bind-address=* + pid-file=/opt/bitnami/mysql/tmp/mysqld.pid + log-error=/opt/bitnami/mysql/logs/mysqld.log + character-set-server=UTF8 + collation-server=utf8_general_ci + slow_query_log=0 + slow_query_log_file=/opt/bitnami/mysql/logs/mysqld.log + long_query_time=10.0 + + [client] + port=3306 + socket=/opt/bitnami/mysql/tmp/mysql.sock + default-character-set=UTF8 + plugin_dir=/opt/bitnami/mysql/lib/plugin + + [manager] + port=3306 + socket=/opt/bitnami/mysql/tmp/mysql.sock + pid-file=/opt/bitnami/mysql/tmp/mysqld.pid + ## @param primary.existingConfigmap Name of existing ConfigMap with MySQL Primary configuration. + ## NOTE: When it's set the 'configuration' parameter is ignored + ## + existingConfigmap: "" + ## @param primary.updateStrategy.type Update strategy type for the MySQL primary statefulset + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies + ## + updateStrategy: + type: RollingUpdate + ## @param primary.podAnnotations Additional pod annotations for MySQL primary pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + podAnnotations: {} + ## @param primary.podAffinityPreset MySQL 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 MySQL 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 + ## MySQL Primary node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## + nodeAffinityPreset: + ## @param primary.nodeAffinityPreset.type MySQL primary node affinity preset type. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` + ## + type: "" + ## @param primary.nodeAffinityPreset.key MySQL 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 MySQL 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 MySQL 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 MySQL primary pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + ## @param primary.tolerations Tolerations for MySQL primary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + ## @param primary.priorityClassName MySQL primary pods' priorityClassName + ## + priorityClassName: "" + ## @param primary.runtimeClassName MySQL primary pods' runtimeClassName + ## + runtimeClassName: "" + ## @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.terminationGracePeriodSeconds In seconds, time the given to the MySQL primary pod needs to terminate gracefully + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods + ## + terminationGracePeriodSeconds: "" + ## @param primary.topologySpreadConstraints Topology Spread Constraints for pod assignment + ## https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ + ## The value is evaluated as a template + ## + topologySpreadConstraints: [] + ## @param primary.podManagementPolicy podManagementPolicy to manage scaling operation of MySQL primary pods + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies + ## + podManagementPolicy: "" + ## MySQL 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 MySQL primary pods + ## @param primary.podSecurityContext.fsGroup Group ID for the mounted volumes' filesystem + ## + podSecurityContext: + enabled: true + fsGroup: 1001 + ## MySQL 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 MySQL primary container securityContext + ## @param primary.containerSecurityContext.runAsUser User ID for the MySQL primary container + ## @param primary.containerSecurityContext.runAsNonRoot Set MySQL primary container's Security Context runAsNonRoot + ## + containerSecurityContext: + enabled: true + runAsUser: 1001 + runAsNonRoot: true + ## MySQL 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 MySQL primary containers + ## @param primary.resources.requests The requested resources for MySQL primary containers + ## + resources: + ## Example: + ## limits: + ## cpu: 250m + ## memory: 256Mi + limits: {} + ## Examples: + ## requests: + ## cpu: 250m + ## 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 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: 5 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 3 + successThreshold: 1 + ## Configure extra options for readiness probe + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes + ## @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: 5 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 3 + successThreshold: 1 + ## Configure extra options for startupProbe probe + ## 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: true + initialDelaySeconds: 15 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 10 + successThreshold: 1 + ## @param primary.customLivenessProbe Override default liveness probe for MySQL primary containers + ## + customLivenessProbe: {} + ## @param primary.customReadinessProbe Override default readiness probe for MySQL primary containers + ## + customReadinessProbe: {} + ## @param primary.customStartupProbe Override default startup probe for MySQL primary containers + ## + customStartupProbe: {} + ## @param primary.extraFlags MySQL 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 MySQL primary containers + ## E.g. + ## extraEnvVars: + ## - name: TZ + ## value: "Europe/Paris" + ## + extraEnvVars: [] + ## @param primary.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for MySQL primary containers + ## + extraEnvVarsCM: "" + ## @param primary.extraEnvVarsSecret Name of existing Secret containing extra env vars for MySQL 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 MySQL primary replicas using a `PersistentVolumeClaim`. If false, use emptyDir + ## + enabled: true + ## @param primary.persistence.existingClaim Name of an existing `PersistentVolumeClaim` for MySQL primary replicas + ## NOTE: When it's set the rest of persistence parameters are ignored + ## + existingClaim: "" + ## @param primary.persistence.subPath The name of a volume's sub path to mount for persistence + ## + subPath: "" + ## @param primary.persistence.storageClass MySQL 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 MySQL primary persistent volume claim annotations + ## + annotations: {} + ## @param primary.persistence.accessModes MySQL primary persistent volume access Modes + ## + accessModes: + - ReadWriteOnce + ## @param primary.persistence.size MySQL 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 MySQL Primary pod(s) + ## + extraVolumes: [] + ## @param primary.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the MySQL Primary container(s) + ## + extraVolumeMounts: [] + ## @param primary.initContainers Add additional init containers for the MySQL Primary pod(s) + ## + initContainers: [] + ## @param primary.sidecars Add additional sidecar containers for the MySQL Primary pod(s) + ## + sidecars: [] + ## MySQL Primary Service parameters + ## + service: + ## @param primary.service.type MySQL Primary K8s service type + ## + type: ClusterIP + ## @param primary.service.ports.mysql MySQL Primary K8s service port + ## + ports: + mysql: 3306 + ## @param primary.service.nodePorts.mysql MySQL Primary K8s service node port + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## + nodePorts: + mysql: "" + ## @param primary.service.clusterIP MySQL Primary K8s service clusterIP IP + ## e.g: + ## clusterIP: None + ## + clusterIP: "" + ## @param primary.service.loadBalancerIP MySQL Primary loadBalancerIP if service type is `LoadBalancer` + ## Set the LoadBalancer service type to internal only + ## 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 Addresses that are allowed when MySQL 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 Additional custom annotations for MySQL primary service + ## + 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: {} + ## Headless service properties + ## + headless: + ## @param primary.service.headless.annotations Additional custom annotations for headless MySQL primary service. + ## + annotations: {} + + ## MySQL 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 MySQL primary pods + ## + create: false + ## @param primary.pdb.minAvailable Minimum number/percentage of MySQL primary pods that should remain scheduled + ## + minAvailable: 1 + ## @param primary.pdb.maxUnavailable Maximum number/percentage of MySQL primary pods that may be made unavailable + ## + maxUnavailable: "" + ## @param primary.podLabels MySQL Primary pod label. If labels are same as commonLabels , this will take precedence + ## + podLabels: {} + +## @section MySQL Secondary parameters + +secondary: + ## @param secondary.name Name of the secondary database (eg secondary, slave, ...) + ## + name: secondary + ## @param secondary.replicaCount Number of MySQL secondary replicas + ## + replicaCount: 1 + ## @param secondary.hostAliases Deployment pod host aliases + ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ + ## + hostAliases: [] + ## @param secondary.command Override default container command on MySQL Secondary container(s) (useful when using custom images) + ## + command: [] + ## @param secondary.args Override default container args on MySQL Secondary container(s) (useful when using custom images) + ## + args: [] + ## @param secondary.lifecycleHooks for the MySQL Secondary container(s) to automate configuration before or after startup + ## + lifecycleHooks: {} + ## @param secondary.configuration [string] Configure MySQL Secondary with a custom my.cnf file + ## ref: https://mysql.com/kb/en/mysql/configuring-mysql-with-mycnf/#example-of-configuration-file + ## + configuration: |- + [mysqld] + default_authentication_plugin=mysql_native_password + skip-name-resolve + explicit_defaults_for_timestamp + basedir=/opt/bitnami/mysql + plugin_dir=/opt/bitnami/mysql/lib/plugin + port=3306 + socket=/opt/bitnami/mysql/tmp/mysql.sock + datadir=/bitnami/mysql/data + tmpdir=/opt/bitnami/mysql/tmp + max_allowed_packet=16M + bind-address=* + pid-file=/opt/bitnami/mysql/tmp/mysqld.pid + log-error=/opt/bitnami/mysql/logs/mysqld.log + character-set-server=UTF8 + collation-server=utf8_general_ci + slow_query_log=0 + slow_query_log_file=/opt/bitnami/mysql/logs/mysqld.log + long_query_time=10.0 + + [client] + port=3306 + socket=/opt/bitnami/mysql/tmp/mysql.sock + default-character-set=UTF8 + plugin_dir=/opt/bitnami/mysql/lib/plugin + + [manager] + port=3306 + socket=/opt/bitnami/mysql/tmp/mysql.sock + pid-file=/opt/bitnami/mysql/tmp/mysqld.pid + ## @param secondary.existingConfigmap Name of existing ConfigMap with MySQL Secondary configuration. + ## NOTE: When it's set the 'configuration' parameter is ignored + ## + existingConfigmap: "" + ## @param secondary.updateStrategy.type Update strategy type for the MySQL secondary statefulset + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies + ## + updateStrategy: + type: RollingUpdate + ## @param secondary.podAnnotations Additional pod annotations for MySQL secondary pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + podAnnotations: {} + ## @param secondary.podAffinityPreset MySQL 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 MySQL 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 + ## Allowed values: soft, hard + ## + podAntiAffinityPreset: soft + ## MySQL Secondary node affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## + nodeAffinityPreset: + ## @param secondary.nodeAffinityPreset.type MySQL secondary node affinity preset type. Ignored if `secondary.affinity` is set. Allowed values: `soft` or `hard` + ## + type: "" + ## @param secondary.nodeAffinityPreset.key MySQL 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 MySQL 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 MySQL 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 MySQL secondary pods assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + ## @param secondary.tolerations Tolerations for MySQL secondary pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + ## @param secondary.priorityClassName MySQL secondary pods' priorityClassName + ## + priorityClassName: "" + ## @param secondary.runtimeClassName MySQL secondary pods' runtimeClassName + ## + 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.terminationGracePeriodSeconds In seconds, time the given to the MySQL secondary pod needs to terminate gracefully + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods + ## + terminationGracePeriodSeconds: "" + ## @param secondary.topologySpreadConstraints Topology Spread Constraints for pod assignment + ## https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ + ## The value is evaluated as a template + ## + topologySpreadConstraints: [] + ## @param secondary.podManagementPolicy podManagementPolicy to manage scaling operation of MySQL secondary pods + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies + ## + podManagementPolicy: "" + ## MySQL 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 MySQL secondary pods + ## @param secondary.podSecurityContext.fsGroup Group ID for the mounted volumes' filesystem + ## + podSecurityContext: + enabled: true + fsGroup: 1001 + ## MySQL 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 MySQL secondary container securityContext + ## @param secondary.containerSecurityContext.runAsUser User ID for the MySQL secondary container + ## @param secondary.containerSecurityContext.runAsNonRoot Set MySQL secondary container's Security Context runAsNonRoot + ## + containerSecurityContext: + enabled: true + runAsUser: 1001 + runAsNonRoot: true + ## MySQL 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 MySQL secondary containers + ## @param secondary.resources.requests The requested resources for MySQL secondary containers + ## + resources: + ## Example: + ## limits: + ## cpu: 250m + ## memory: 256Mi + limits: {} + ## Examples: + ## requests: + ## cpu: 250m + ## 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 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: 5 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 3 + successThreshold: 1 + ## Configure extra options for readiness probe + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes + ## @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: 5 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 3 + successThreshold: 1 + ## Configure extra options for startupProbe probe + ## 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: true + initialDelaySeconds: 15 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 15 + successThreshold: 1 + ## @param secondary.customLivenessProbe Override default liveness probe for MySQL secondary containers + ## + customLivenessProbe: {} + ## @param secondary.customReadinessProbe Override default readiness probe for MySQL secondary containers + ## + customReadinessProbe: {} + ## @param secondary.customStartupProbe Override default startup probe for MySQL secondary containers + ## + customStartupProbe: {} + ## @param secondary.extraFlags MySQL 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 An array to add extra environment variables on MySQL secondary containers + ## E.g. + ## extraEnvVars: + ## - name: TZ + ## value: "Europe/Paris" + ## + extraEnvVars: [] + ## @param secondary.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for MySQL secondary containers + ## + extraEnvVarsCM: "" + ## @param secondary.extraEnvVarsSecret Name of existing Secret containing extra env vars for MySQL 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 MySQL secondary replicas using a `PersistentVolumeClaim` + ## + enabled: true + ## @param secondary.persistence.existingClaim Name of an existing `PersistentVolumeClaim` for MySQL secondary replicas + ## NOTE: When it's set the rest of persistence parameters are ignored + ## + existingClaim: "" + ## @param secondary.persistence.subPath The name of a volume's sub path to mount for persistence + ## + subPath: "" + ## @param secondary.persistence.storageClass MySQL 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 MySQL secondary persistent volume claim annotations + ## + annotations: {} + ## @param secondary.persistence.accessModes MySQL secondary persistent volume access Modes + ## + accessModes: + - ReadWriteOnce + ## @param secondary.persistence.size MySQL 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 MySQL secondary pod(s) + ## + extraVolumes: [] + ## @param secondary.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the MySQL secondary container(s) + ## + extraVolumeMounts: [] + ## @param secondary.initContainers Add additional init containers for the MySQL secondary pod(s) + ## + initContainers: [] + ## @param secondary.sidecars Add additional sidecar containers for the MySQL secondary pod(s) + ## + sidecars: [] + ## MySQL Secondary Service parameters + ## + service: + ## @param secondary.service.type MySQL secondary Kubernetes service type + ## + type: ClusterIP + ## @param secondary.service.ports.mysql MySQL secondary Kubernetes service port + ## + ports: + mysql: 3306 + ## @param secondary.service.nodePorts.mysql MySQL secondary Kubernetes service node port + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## + nodePorts: + mysql: "" + ## @param secondary.service.clusterIP MySQL secondary Kubernetes service clusterIP IP + ## e.g: + ## clusterIP: None + ## + clusterIP: "" + ## @param secondary.service.loadBalancerIP MySQL secondary loadBalancerIP if service type is `LoadBalancer` + ## Set the LoadBalancer service type to internal only + ## 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 Addresses that are allowed when MySQL 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 Additional custom annotations for MySQL secondary service + ## + 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: {} + ## Headless service properties + ## + headless: + ## @param secondary.service.headless.annotations Additional custom annotations for headless MySQL secondary service. + ## + annotations: {} + + ## MySQL 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 MySQL secondary pods + ## + create: false + ## @param secondary.pdb.minAvailable Minimum number/percentage of MySQL secondary pods that should remain scheduled + ## + minAvailable: 1 + ## @param secondary.pdb.maxUnavailable Maximum number/percentage of MySQL secondary pods that may be made unavailable + ## + maxUnavailable: "" + ## @param secondary.podLabels Additional pod labels for MySQL secondary pods + ## + podLabels: {} + +## @section RBAC parameters + +## MySQL 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 MySQL pods + ## + create: true + ## @param serviceAccount.name Name of the created ServiceAccount + ## If not set and create is true, a name is generated using the mysql.fullname template + ## + name: "" + ## @param serviceAccount.annotations Annotations for MySQL Service Account + ## + annotations: {} + ## @param serviceAccount.automountServiceAccountToken Automount service account token for the server service account + ## + automountServiceAccountToken: true + +## Role Based Access +## ref: https://kubernetes.io/docs/admin/authorization/rbac/ +## +rbac: + ## @param rbac.create Whether to create & use RBAC resources or not + ## + create: false + ## @param rbac.rules Custom RBAC rules to set + ## e.g: + ## rules: + ## - apiGroups: + ## - "" + ## resources: + ## - pods + ## verbs: + ## - get + ## - list + ## + rules: [] + +## @section Network Policy + +## MySQL Nework Policy configuration +## +networkPolicy: + ## @param networkPolicy.enabled Enable creation of NetworkPolicy resources + ## + enabled: false + ## @param networkPolicy.allowExternal The Policy model to apply. + ## When set to false, only pods with the correct + ## client label will have network access to the port MySQL is listening + ## on. When true, MySQL will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + ## @param networkPolicy.explicitNamespacesSelector A Kubernetes LabelSelector to explicitly select namespaces from which ingress traffic could be allowed to MySQL + ## If explicitNamespacesSelector is missing or set to {}, only client Pods that are in the networkPolicy's namespace + ## and that match other criteria, the ones that have the good label, can reach the DB. + ## But sometimes, we want the DB to be accessible to clients from other namespaces, in this case, we can use this + ## LabelSelector to select these namespaces, note that the networkPolicy's namespace should also be explicitly added. + ## + ## Example: + ## explicitNamespacesSelector: + ## matchLabels: + ## role: frontend + ## matchExpressions: + ## - {key: role, operator: In, values: [frontend]} + ## + explicitNamespacesSelector: {} + +## @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-r70 + 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/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## @param volumePermissions.resources Init container volume-permissions resources + ## + resources: {} + +## @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-r76 + 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/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## MySQL Prometheus exporter service parameters + ## Mysqld Prometheus exporter liveness and readiness probes + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes + ## @param metrics.service.type Kubernetes service type for MySQL Prometheus Exporter + ## @param metrics.service.port MySQL Prometheus Exporter service port + ## @param metrics.service.annotations [object] Prometheus exporter service annotations + ## + service: + type: ClusterIP + port: 9104 + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "{{ .Values.metrics.service.port }}" + ## @param metrics.extraArgs.primary Extra args to be passed to mysqld_exporter on Primary pods + ## @param metrics.extraArgs.secondary Extra args to be passed to mysqld_exporter on Secondary pods + ## 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: [] + ## 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 MySQL prometheus exporter containers + ## @param metrics.resources.requests The requested resources for MySQL prometheus exporter containers + ## + resources: + ## Example: + ## limits: + ## cpu: 100m + ## memory: 256Mi + limits: {} + ## Examples: + ## requests: + ## cpu: 100m + ## memory: 256Mi + requests: {} + ## Mysqld Prometheus exporter liveness probe + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-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 + ## Mysqld Prometheus exporter readiness probe + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-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 Specify the namespace in which the serviceMonitor resource will be created + ## + 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 Specify the 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.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.honorLabels Specify honorLabels parameter to add the scrape endpoint + ## + honorLabels: false + ## @param metrics.serviceMonitor.labels Used to pass Labels that are used by the Prometheus installed in your cluster to select Service Monitors to work with + ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#prometheusspec + ## + labels: {} + ## @param metrics.serviceMonitor.annotations ServiceMonitor annotations + ## + annotations: {} + + ## Prometheus Operator prometheusRule configuration + ## + prometheusRule: + ## @param metrics.prometheusRule.enabled 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: Mysql-Down + ## expr: absent(up{job="mysql"} == 1) + ## for: 5m + ## labels: + ## severity: warning + ## service: mariadb + ## annotations: + ## message: 'MariaDB instance {{`{{`}} $labels.instance {{`}}`}} is down' + ## summary: MariaDB instance is down + ## + rules: [] diff --git a/deployment/deployment/quanxiang_charts/builder/.helmignore b/deployment/charts/quanxiang/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/builder/.helmignore rename to deployment/charts/quanxiang/.helmignore diff --git a/deployment/charts/quanxiang/Chart.lock b/deployment/charts/quanxiang/Chart.lock new file mode 100644 index 0000000..07fb494 --- /dev/null +++ b/deployment/charts/quanxiang/Chart.lock @@ -0,0 +1,99 @@ +dependencies: +- name: mysql + repository: file://../mysql + version: 9.4.6 +- name: redis-cluster + repository: file://../redis-cluster + version: 7.1.0 +- name: mongodb + repository: file://../mongodb + version: 13.6.2 +- name: minio + repository: file://../minio + version: 5.0.33 +- name: fluent-bit + repository: file://../fluent-bit + version: 2.10.3 +- name: kafka + repository: file://../kafka + version: 20.0.2 +- name: elasticsearch + repository: file://../elasticsearch + version: 17.9.24 +- name: polygate + repository: "" + version: 0.1.0 +- name: audit + repository: "" + version: 0.1.0 +- name: entrepot + repository: "" + version: 0.1.0 +- name: fileserver + repository: "" + version: 0.1.0 +- name: implant + repository: "" + version: 0.1.0 +- name: serving + repository: "" + version: 0.1.0 +- name: appcenter + repository: "" + version: 0.1.0 +- name: form + repository: "" + version: 0.1.0 +- name: flow + repository: "" + version: 0.1.0 +- name: goalie + repository: "" + version: 0.1.0 +- name: polyapi + repository: "" + version: 0.1.0 +- name: process + repository: "" + version: 0.1.0 +- name: kms + repository: "" + version: 0.1.0 +- name: search + repository: "" + version: 0.1.0 +- name: dispatcher + repository: "" + version: 0.1.0 +- name: organizations + repository: "" + version: 0.1.0 +- name: persona + repository: "" + version: 0.1.0 +- name: faas + repository: "" + version: 0.1.0 +- name: message + repository: "" + version: 0.1.0 +- name: warden + repository: "" + version: 0.1.0 +- name: web-process + repository: "" + version: 0.1.0 +- name: qxp-web-nginx + repository: "" + version: 0.1.0 +- name: qxp-web-home + repository: "" + version: 0.1.0 +- name: qxp-web-portal + repository: "" + version: 0.1.0 +- name: qxp-web-vendors + repository: "" + version: 0.1.0 +digest: sha256:8d1580b5818330eabbb5090eafb8fe3059d5901e8bda499e487f947556aa98aa +generated: "2023-01-12T15:13:07.654347+08:00" diff --git a/deployment/charts/quanxiang/Chart.yaml b/deployment/charts/quanxiang/Chart.yaml new file mode 100644 index 0000000..ef0aad8 --- /dev/null +++ b/deployment/charts/quanxiang/Chart.yaml @@ -0,0 +1,111 @@ +apiVersion: v2 +name: quanxiang +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" + + +dependencies: + - name: mysql + version: 9.4.6 + repository: "file://../mysql" + condition: mysql.enabled + - name: redis-cluster + version: 7.1.0 + repository: "file://../redis-cluster" + condition: redis-cluster.enabled + - name: mongodb + version: 13.6.2 + repository: "file://../mongodb" + condition: mongodb.enabled + - name: minio + version: 5.0.33 + repository: "file://../minio" + condition: minio.enabled + - name: fluent-bit + version: 2.10.3 + repository: "file://../fluent-bit" + condition: fluent-bit.enabled + - name: kafka + version: 20.0.2 + repository: "file://../kafka" + condition: kafka.enabled + - name: elasticsearch + version: 17.9.24 + repository: "file://../elasticsearch" + condition: elasticsearch.enabled + + # backend + - name: polygate + version: "0.1.0" + - name: audit + version: "0.1.0" + - name: entrepot + version: "0.1.0" + - name: fileserver + version: "0.1.0" + - name: implant + version: "0.1.0" + - name: serving + version: "0.1.0" + - name: appcenter + version: "0.1.0" + - name: form + version: "0.1.0" + - name: flow + version: "0.1.0" + - name: goalie + version: "0.1.0" + - name: polyapi + version: "0.1.0" + - name: process + version: "0.1.0" + - name: kms + version: "0.1.0" + - name: search + version: "0.1.0" + - name: dispatcher + version: "0.1.0" + - name: organizations + version: "0.1.0" + - name: persona + version: "0.1.0" + - name: faas + version: "0.1.0" + - name: message + version: "0.1.0" + - name: warden + version: "0.1.0" + # - name: builder + # version: "0.1.0" + + # web + - name: web-process + version: "0.1.0" + - name: qxp-web-nginx + version: "0.1.0" + - name: qxp-web-home + version: "0.1.0" + - name: qxp-web-portal + version: "0.1.0" + - name: qxp-web-vendors + version: "0.1.0" \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/app-center/.helmignore b/deployment/charts/quanxiang/charts/appcenter/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/app-center/.helmignore rename to deployment/charts/quanxiang/charts/appcenter/.helmignore diff --git a/deployment/charts/quanxiang/charts/appcenter/Chart.yaml b/deployment/charts/quanxiang/charts/appcenter/Chart.yaml new file mode 100644 index 0000000..ac6f762 --- /dev/null +++ b/deployment/charts/quanxiang/charts/appcenter/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: appcenter +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/deployment/deployment/quanxiang_charts/app-center/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/appcenter/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/app-center/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/appcenter/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/app-center/templates/configmap.yaml b/deployment/charts/quanxiang/charts/appcenter/templates/configmap.yaml similarity index 80% rename from deployment/deployment/quanxiang_charts/app-center/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/appcenter/templates/configmap.yaml index 850fabf..079fd75 100644 --- a/deployment/deployment/quanxiang_charts/app-center/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/appcenter/templates/configmap.yaml @@ -2,7 +2,7 @@ kind: ConfigMap apiVersion: v1 metadata: name: app-center - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} data: config.yml: > @@ -38,19 +38,19 @@ data: ----------------------------------- mysql: - db: {{ .Values.config.mysql.db }} - host: {{ .Values.config.mysql.host }} - user: {{ .Values.config.mysql.user }} - password: {{ .Values.config.mysql.password }} - log: {{ .Values.config.mysql.log }} + db: {{ .Values.mysql.db }} + host: {{ .Values.mysql.host }} + user: {{ .Values.mysql.user }} + password: {{ .Values.mysql.password }} + log: {{ .Values.mysql.log }} redis: - {{- with .Values.config.redis.addrs }} + {{- with .Values.redis.addrs }} addrs: {{- toYaml . | nindent 8 }} {{- end }} - username: {{ .Values.config.redis.username }} - password: {{ .Values.config.redis.password }} + username: {{ .Values.redis.username }} + password: {{ .Values.redis.password }} # comply with zap log specification diff --git a/deployment/deployment/quanxiang_charts/app-center/templates/deployment.yaml b/deployment/charts/quanxiang/charts/appcenter/templates/deployment.yaml similarity index 95% rename from deployment/deployment/quanxiang_charts/app-center/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/appcenter/templates/deployment.yaml index fb1af08..1da52f7 100644 --- a/deployment/deployment/quanxiang_charts/app-center/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/appcenter/templates/deployment.yaml @@ -2,7 +2,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: app-center - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: app-center app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} @@ -57,7 +57,7 @@ spec: terminationMessagePolicy: File imagePullPolicy: IfNotPresent - name: container - image: '{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }}' + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' ports: - name: app-center containerPort: 80 diff --git a/deployment/deployment/quanxiang_charts/app-center/templates/service.yaml b/deployment/charts/quanxiang/charts/appcenter/templates/service.yaml similarity index 94% rename from deployment/deployment/quanxiang_charts/app-center/templates/service.yaml rename to deployment/charts/quanxiang/charts/appcenter/templates/service.yaml index 7d09cd9..24641cc 100644 --- a/deployment/deployment/quanxiang_charts/app-center/templates/service.yaml +++ b/deployment/charts/quanxiang/charts/appcenter/templates/service.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: app-center - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: app-center app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} diff --git a/deployment/deployment/quanxiang_charts/app-center/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/appcenter/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/app-center/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/appcenter/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/appcenter/values.yaml b/deployment/charts/quanxiang/charts/appcenter/values.yaml new file mode 100644 index 0000000..3019483 --- /dev/null +++ b/deployment/charts/quanxiang/charts/appcenter/values.yaml @@ -0,0 +1,22 @@ +image: + repository: quanxiang/appcenter + tag: v2.0.0 +imagePullSecrets: "" +namespace: "" + +mysql: {} +redis: + addrs: + - redis-cluster-0.redis-cluster-headless:6379 + - redis-cluster-1.redis-cluster-headless:6379 + - redis-cluster-2.redis-cluster-headless:6379 + +service: + type: ClusterIP + port: 80 + rpcPort: 0 + +app: + kubernetes: + io: + name: backend diff --git a/deployment/deployment/quanxiang_charts/audit/.helmignore b/deployment/charts/quanxiang/charts/audit/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/audit/.helmignore rename to deployment/charts/quanxiang/charts/audit/.helmignore diff --git a/deployment/charts/quanxiang/charts/audit/Chart.yaml b/deployment/charts/quanxiang/charts/audit/Chart.yaml new file mode 100644 index 0000000..3ed0c6c --- /dev/null +++ b/deployment/charts/quanxiang/charts/audit/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: audit +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/deployment/deployment/kibana/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/audit/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/kibana/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/audit/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/audit/templates/configmap.yaml b/deployment/charts/quanxiang/charts/audit/templates/configmap.yaml similarity index 86% rename from deployment/deployment/quanxiang_charts/audit/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/audit/templates/configmap.yaml index 2a20505..e303958 100644 --- a/deployment/deployment/quanxiang_charts/audit/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/audit/templates/configmap.yaml @@ -2,7 +2,7 @@ kind: ConfigMap apiVersion: v1 metadata: name: audit - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} data: config.yml: | @@ -44,15 +44,15 @@ data: # -------------------- elastic -------------------- elastic: - {{- with .Values.config.elastic.host }} + {{- with.Values.elastic.host }} host: {{- toYaml . | nindent 8 }} {{- end }} - log: {{ .Values.config.elastic.log }} + log: {{ .Values.elastic.log }} # -------------------- kafka -------------------- kafka: - {{- with .Values.config.kafka.broker }} + {{- with .Values.kafka.broker }} broker: {{- toYaml . | nindent 8 }} {{- end }} \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/audit/templates/deployment.yaml b/deployment/charts/quanxiang/charts/audit/templates/deployment.yaml similarity index 94% rename from deployment/deployment/quanxiang_charts/audit/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/audit/templates/deployment.yaml index 09d5a84..ce45da3 100644 --- a/deployment/deployment/quanxiang_charts/audit/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/audit/templates/deployment.yaml @@ -34,7 +34,7 @@ spec: containers: - name: container-kudq8k imagePullPolicy: Always - image: '{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }}' + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' ports: - name: tcp-80 protocol: TCP diff --git a/deployment/deployment/quanxiang_charts/audit/templates/service.yaml b/deployment/charts/quanxiang/charts/audit/templates/service.yaml similarity index 93% rename from deployment/deployment/quanxiang_charts/audit/templates/service.yaml rename to deployment/charts/quanxiang/charts/audit/templates/service.yaml index d8dbb9d..78e49fb 100644 --- a/deployment/deployment/quanxiang_charts/audit/templates/service.yaml +++ b/deployment/charts/quanxiang/charts/audit/templates/service.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: audit - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: audit version: v1 diff --git a/deployment/deployment/quanxiang_charts/audit/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/audit/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/audit/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/audit/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/audit/values.yaml b/deployment/charts/quanxiang/charts/audit/values.yaml new file mode 100644 index 0000000..5456562 --- /dev/null +++ b/deployment/charts/quanxiang/charts/audit/values.yaml @@ -0,0 +1,20 @@ +image: + repository: quanxiang/audit + tag: v2.0.0 +imagePullSecrets: "" +namespace: "" +elastic: + log: true + host: + - http://elasticsearch-master:9200 +kafka: + broker: + - kafka:9092 +service: + type: ClusterIP + port: 80 + rpcPort: 0 +app: + kubernetes: + io: + name: backend \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/entrepot/.helmignore b/deployment/charts/quanxiang/charts/builder/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/entrepot/.helmignore rename to deployment/charts/quanxiang/charts/builder/.helmignore diff --git a/deployment/deployment/quanxiang_charts/builder/Chart.yaml b/deployment/charts/quanxiang/charts/builder/Chart.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/builder/Chart.yaml rename to deployment/charts/quanxiang/charts/builder/Chart.yaml diff --git a/deployment/deployment/quanxiang_charts/builder/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/builder/templates/_helpers.tpl similarity index 89% rename from deployment/deployment/quanxiang_charts/builder/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/builder/templates/_helpers.tpl index cb1c1ee..f049896 100644 --- a/deployment/deployment/quanxiang_charts/builder/templates/_helpers.tpl +++ b/deployment/charts/quanxiang/charts/builder/templates/_helpers.tpl @@ -60,3 +60,7 @@ Create the name of the service account to use {{- default "default" .Values.serviceAccount.name }} {{- end }} {{- end }} + +{{- define "imagePullSecret" }} +{{- printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}}}" .Values.docker.registry (printf "%s:%s" .Values.docker.username .Values.docker.password | b64enc) | b64enc }} +{{- end }} \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/builder/templates/pipeline/build.yaml b/deployment/charts/quanxiang/charts/builder/templates/pipeline/build.yaml similarity index 98% rename from deployment/deployment/quanxiang_charts/builder/templates/pipeline/build.yaml rename to deployment/charts/quanxiang/charts/builder/templates/pipeline/build.yaml index 8d8e023..1cc9a76 100644 --- a/deployment/deployment/quanxiang_charts/builder/templates/pipeline/build.yaml +++ b/deployment/charts/quanxiang/charts/builder/templates/pipeline/build.yaml @@ -2,6 +2,7 @@ apiVersion: tekton.dev/v1beta1 kind: Pipeline metadata: name: buildpacks + namespace: {{ .Values.namespace }} labels: app.kubernetes.io/version: "0.1" annotations: diff --git a/deployment/deployment/quanxiang_charts/builder/templates/pipeline/register-api.yaml b/deployment/charts/quanxiang/charts/builder/templates/pipeline/register-api.yaml similarity index 80% rename from deployment/deployment/quanxiang_charts/builder/templates/pipeline/register-api.yaml rename to deployment/charts/quanxiang/charts/builder/templates/pipeline/register-api.yaml index 787ecb8..58aff71 100644 --- a/deployment/deployment/quanxiang_charts/builder/templates/pipeline/register-api.yaml +++ b/deployment/charts/quanxiang/charts/builder/templates/pipeline/register-api.yaml @@ -2,7 +2,7 @@ apiVersion: tekton.dev/v1beta1 kind: Pipeline metadata: name: register-polyapi - namespace: builder + namespace: {{ .Values.namespace }} spec: description: >- Go to the polyapi there to register the swagger document @@ -39,16 +39,16 @@ spec: - name: url value: $(params.SOURCE_URL) - name: gitInitImage - value: docker.io/quanxiang/grc.io.git-init:v0.29.0 + value: {{ .Values.gitInitImage }} - name: PROJECT_NAME value: "$(params.PROJECT_NAME)" - name: PROJECT_TITLE value: "$(params.PROJECT_TITLE)" - name: SWAGGER_IMAGE - value: '{{ .Values.image.repo }}/swag:{{ .Values.image.tag }}' + value: {{ .Values.swagImage }} - name: OPERATE_ID value: "$(params.OPERATE_ID)" - name: HOST value: "$(params.HOST)" - name: POLYAPI_PATH - value: http://polyapi.{{.Values.lowcode}}.svc.cluster.local:9090/api/v1/polyapi/inner/regSwaggerAlone/system/app/$(params.APPID)/raw/faas/$(params.GROUP_NAME)/$(params.PROJECT_NAME) + value: http://polyapi.{{.Values.global.namespace}}.svc.cluster.local:9090/api/v1/polyapi/inner/regSwaggerAlone/system/app/$(params.APPID)/raw/faas/$(params.GROUP_NAME)/$(params.PROJECT_NAME) diff --git a/deployment/charts/quanxiang/charts/builder/templates/secrets.yaml b/deployment/charts/quanxiang/charts/builder/templates/secrets.yaml new file mode 100644 index 0000000..a27f078 --- /dev/null +++ b/deployment/charts/quanxiang/charts/builder/templates/secrets.yaml @@ -0,0 +1,22 @@ +kind: Secret +apiVersion: v1 +type: kubernetes.io/ssh-auth +metadata: + name: {{ .Values.git.name }} + namespace: {{ .Values.namespace }} + annotations: + tekton.dev/git-0: {{ .Values.git.host }} +data: + known_hosts: >- + {{ .Values.git.known_hosts_scan }} + ssh-privatekey: >- + {{ .Values.git.sshPrivatekey }} +--- +apiVersion: v1 +kind: Secret +type: kubernetes.io/dockerconfigjson +metadata: + name: {{ .Values.docker.name }} + namespace: {{ .Values.namespace }} +data: + .dockerconfigjson: {{ template "imagePullSecret" . }} \ No newline at end of file diff --git a/deployment/charts/quanxiang/charts/builder/templates/serviceaccount.yaml b/deployment/charts/quanxiang/charts/builder/templates/serviceaccount.yaml new file mode 100644 index 0000000..ed96b56 --- /dev/null +++ b/deployment/charts/quanxiang/charts/builder/templates/serviceaccount.yaml @@ -0,0 +1,11 @@ +{{- if .Values.global.faas.enabled -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: {{ .Values.namespace }} + name: builder +secrets: + - name: rsa + - name: faas-git +{{- end }} + diff --git a/deployment/deployment/quanxiang_charts/builder/templates/task/git-clone.yaml b/deployment/charts/quanxiang/charts/builder/templates/task/git-clone.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/builder/templates/task/git-clone.yaml rename to deployment/charts/quanxiang/charts/builder/templates/task/git-clone.yaml diff --git a/deployment/deployment/quanxiang_charts/builder/templates/task/register-api.yaml b/deployment/charts/quanxiang/charts/builder/templates/task/register-api.yaml similarity index 99% rename from deployment/deployment/quanxiang_charts/builder/templates/task/register-api.yaml rename to deployment/charts/quanxiang/charts/builder/templates/task/register-api.yaml index 9b14fbb..a8a4da1 100644 --- a/deployment/deployment/quanxiang_charts/builder/templates/task/register-api.yaml +++ b/deployment/charts/quanxiang/charts/builder/templates/task/register-api.yaml @@ -202,7 +202,7 @@ spec: printf "%s" "${PARAM_URL}" > "$(results.url.path)" - name: register-swagger image: $(params.SWAGGER_IMAGE) - imagePullPolicy: Always + imagePullPolicy: IfNotPresent script: | #!/bin/sh cd $(workspaces.source.path) diff --git a/deployment/charts/quanxiang/charts/builder/values.yaml b/deployment/charts/quanxiang/charts/builder/values.yaml new file mode 100644 index 0000000..49c6640 --- /dev/null +++ b/deployment/charts/quanxiang/charts/builder/values.yaml @@ -0,0 +1,19 @@ +image: + name: "" + repo: docker.io/quanxiang + tag: v1.1.2 +namespace: "" +gitInitImage: docker.io/quanxiang/grc.io.git-init:v0.29.0 +swageImage: docker.io/quanxiang/swag:v1.1.2 +docker: + name: faas-docker + +git: + name: rsa + host: "" # git server的访问地址,例如:http://git.quanxiang.dev 或者 http://192.168.0.3 + known_hosts_scan: "" # 使用 ssh-keyscan -p 22端口 gitlab域名或者ip |base64 -w 0 生成 + sshPrivatekey: "" # 使用 ssh-keygen -t rsa -f git_rsa -C "admin@quanxiang.dev" 生成ssh key, 将私钥使用base64编码, cat git_rsa|base64 -w 0 + gitSSHAddress: "" # git server 的域名或者IP,例如:git.quanxiang.dev 或者 192.168.0.3 + gitSSHPort: 22 # git server 对外暴露的ssh端口,例如:22 + token: "" # 将公钥写入gitlab并生成token放到这里 + diff --git a/deployment/deployment/quanxiang_charts/dispatcher/.helmignore b/deployment/charts/quanxiang/charts/dispatcher/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/dispatcher/.helmignore rename to deployment/charts/quanxiang/charts/dispatcher/.helmignore diff --git a/deployment/charts/quanxiang/charts/dispatcher/Chart.yaml b/deployment/charts/quanxiang/charts/dispatcher/Chart.yaml new file mode 100644 index 0000000..e22ad50 --- /dev/null +++ b/deployment/charts/quanxiang/charts/dispatcher/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: dispatcher +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/dispatcher/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/dispatcher/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/dispatcher/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/dispatcher/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/dispatcher/templates/configmap.yaml b/deployment/charts/quanxiang/charts/dispatcher/templates/configmap.yaml similarity index 70% rename from deployment/deployment/quanxiang_charts/dispatcher/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/dispatcher/templates/configmap.yaml index d5f3b06..bf20160 100644 --- a/deployment/deployment/quanxiang_charts/dispatcher/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/dispatcher/templates/configmap.yaml @@ -2,7 +2,7 @@ kind: ConfigMap apiVersion: v1 metadata: name: dispatcher - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} data: config.yml: | @@ -42,23 +42,23 @@ data: # -------------------- kafka -------------------- kafka: - {{- with .Values.config.kafka.broker }} + {{- with .Values.kafka.broker }} broker: {{- toYaml . | nindent 8 }} {{- end }} # -------------------- mysql -------------------- mysql: - db: {{ .Values.config.mysql.db }} - host: {{ .Values.config.mysql.host }} - user: {{ .Values.config.mysql.user }} - password: {{ .Values.config.mysql.password }} - log: {{ .Values.config.mysql.log }} + db: {{ .Values.mysql.db }} + host: {{ .Values.mysql.host }} + user: {{ .Values.mysql.user }} + password: {{ .Values.mysql.password }} + log: {{ or .Values.global.password .Values.mysql.log }} redis: - {{- with .Values.config.redis.addrs }} + {{- with .Values.redis.addrs }} addrs: {{- toYaml . | nindent 8 }} {{- end }} - username: {{ .Values.config.redis.username }} - password: {{ .Values.config.redis.password }} \ No newline at end of file + username: {{ .Values.redis.username }} + password: {{ .Values.redis.password }} \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/dispatcher/templates/deployment.yaml b/deployment/charts/quanxiang/charts/dispatcher/templates/deployment.yaml similarity index 93% rename from deployment/deployment/quanxiang_charts/dispatcher/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/dispatcher/templates/deployment.yaml index bdb5907..23e2041 100644 --- a/deployment/deployment/quanxiang_charts/dispatcher/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/dispatcher/templates/deployment.yaml @@ -2,7 +2,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: dispatcher - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: dispatcher app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} @@ -39,7 +39,7 @@ spec: defaultMode: 420 containers: - name: container - image: '{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }}' + image: '{{ .Values.image.repository}}:{{ .Values.image.tag }}' ports: - name: dispatcher containerPort: 80 diff --git a/deployment/deployment/quanxiang_charts/dispatcher/templates/service.yaml b/deployment/charts/quanxiang/charts/dispatcher/templates/service.yaml similarity index 94% rename from deployment/deployment/quanxiang_charts/dispatcher/templates/service.yaml rename to deployment/charts/quanxiang/charts/dispatcher/templates/service.yaml index 76e1678..d498269 100644 --- a/deployment/deployment/quanxiang_charts/dispatcher/templates/service.yaml +++ b/deployment/charts/quanxiang/charts/dispatcher/templates/service.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: dispatcher - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: dispatcher app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} diff --git a/deployment/deployment/quanxiang_charts/dispatcher/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/dispatcher/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/dispatcher/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/dispatcher/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/dispatcher/values.yaml b/deployment/charts/quanxiang/charts/dispatcher/values.yaml new file mode 100644 index 0000000..ccfcb10 --- /dev/null +++ b/deployment/charts/quanxiang/charts/dispatcher/values.yaml @@ -0,0 +1,34 @@ +image: + repository: docker.io/quanxiang/dispatcher + tag: v2.0.0 +imagePullSecrets: "" +namespace: "" +mysql: {} + +redis: + addrs: + - redis-cluster-0.redis-cluster-headless:6379 + - redis-cluster-1.redis-cluster-headless:6379 + - redis-cluster-2.redis-cluster-headless:6379 + username: "" + password: qxp1234 + +service: + type: ClusterIP + port: 80 + rpcPort: 0 + + +domain: example.com +mongo_host: "" +args: + enabled: true + endpoint: example.com + ip: xx.xx.xx.xx +kafka: + value: kafka.{{.}}.svc.cluster.local:9092 + +app: + kubernetes: + io: + name: backend diff --git a/deployment/charts/quanxiang/charts/elasticsearch-17.9.24.tgz b/deployment/charts/quanxiang/charts/elasticsearch-17.9.24.tgz new file mode 100644 index 0000000000000000000000000000000000000000..f003ad0c39a65426c12109558616002e73c06d01 GIT binary patch literal 93754 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 literal 0 HcmV?d00001 diff --git a/deployment/deployment/quanxiang_charts/faas/.helmignore b/deployment/charts/quanxiang/charts/entrepot/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/faas/.helmignore rename to deployment/charts/quanxiang/charts/entrepot/.helmignore diff --git a/deployment/deployment/quanxiang_charts/entrepot/Chart.yaml b/deployment/charts/quanxiang/charts/entrepot/Chart.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/entrepot/Chart.yaml rename to deployment/charts/quanxiang/charts/entrepot/Chart.yaml diff --git a/deployment/deployment/quanxiang_charts/entrepot/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/entrepot/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/entrepot/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/entrepot/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/entrepot/templates/configmap.yaml b/deployment/charts/quanxiang/charts/entrepot/templates/configmap.yaml similarity index 76% rename from deployment/deployment/quanxiang_charts/entrepot/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/entrepot/templates/configmap.yaml index b354bed..3efb89b 100644 --- a/deployment/deployment/quanxiang_charts/entrepot/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/entrepot/templates/configmap.yaml @@ -2,7 +2,7 @@ kind: ConfigMap apiVersion: v1 metadata: name: entrepot - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} annotations: kubesphere.io/creator: zhenlinding data: @@ -61,17 +61,17 @@ data: # -------------------- mysql -------------------- mysql: - db: {{ .Values.config.mysql.db }} - host: {{ .Values.config.mysql.host }} - user: {{ .Values.config.mysql.user }} - password: {{ .Values.config.mysql.password }} - log: {{ .Values.config.mysql.log }} + db: {{ .Values.mysql.db }} + host: {{ .Values.mysql.host }} + user: {{ .Values.mysql.user }} + password: {{ .Values.mysql.password }} + log: {{ .Values.mysql.log }} redis: - {{- with .Values.config.redis.addrs }} + {{- with .Values.redis.addrs }} addrs: {{- toYaml . | nindent 8 }} {{- end }} - username: {{ .Values.config.redis.username }} - password: {{ .Values.config.redis.password }} + username: {{ .Values.redis.username }} + password: {{ .Values.redis.password }} diff --git a/deployment/deployment/quanxiang_charts/entrepot/templates/deployment.yaml b/deployment/charts/quanxiang/charts/entrepot/templates/deployment.yaml similarity index 84% rename from deployment/deployment/quanxiang_charts/entrepot/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/entrepot/templates/deployment.yaml index 48981f2..21f1fcd 100644 --- a/deployment/deployment/quanxiang_charts/entrepot/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/entrepot/templates/deployment.yaml @@ -2,7 +2,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: entrepot - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: entrepot app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} @@ -38,8 +38,8 @@ spec: name: entrepot defaultMode: 420 containers: - - name: container - image: '{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }}' + - name: entrepot + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' ports: - name: http-web containerPort: 80 @@ -57,12 +57,12 @@ spec: dnsPolicy: ClusterFirst serviceAccountName: default serviceAccount: default - {{- if .Values.args.enabled }} + {{- if .Values.hostAliases.enabled }} hostAliases: - hostnames: - - 'fs.{{ .Values.domain }}' - - 'default.fs.{{ .Values.domain }}' - ip: {{ .Values.args.ip }} + - 'fs.{{ or .Values.global.domain .Values.domain }}' + - 'default.fs.{{ or .Values.global.domain .Values.domain }}' + ip: {{ .Values.hostAliases.ip }} {{- end}} securityContext: {} imagePullSecrets: diff --git a/deployment/deployment/quanxiang_charts/entrepot/templates/service.yaml b/deployment/charts/quanxiang/charts/entrepot/templates/service.yaml similarity index 69% rename from deployment/deployment/quanxiang_charts/entrepot/templates/service.yaml rename to deployment/charts/quanxiang/charts/entrepot/templates/service.yaml index 2614405..d3d20a1 100644 --- a/deployment/deployment/quanxiang_charts/entrepot/templates/service.yaml +++ b/deployment/charts/quanxiang/charts/entrepot/templates/service.yaml @@ -2,10 +2,9 @@ kind: Service apiVersion: v1 metadata: name: entrepot - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: entrepot - app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} app.kubernetes.io/version: v1 version: v1 annotations: @@ -19,7 +18,5 @@ spec: targetPort: 80 selector: app: entrepot - app.kubernetes.io/version: v1 - app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} type: {{ .Values.service.type }} sessionAffinity: None diff --git a/deployment/charts/quanxiang/charts/entrepot/values.yaml b/deployment/charts/quanxiang/charts/entrepot/values.yaml new file mode 100644 index 0000000..9f7014d --- /dev/null +++ b/deployment/charts/quanxiang/charts/entrepot/values.yaml @@ -0,0 +1,23 @@ +image: + repository: docker.io/quanxiang/entrepot + tag: v1.1.2 +imagePullSecrets: "" +namespace: "" +mysql: {} + +redis: {} +domain: example.com + +hostAliases: + enabled: true + ip: 192.168.0.10 + +service: + type: ClusterIP + port: 80 + rpcPort: 0 + +app: + kubernetes: + io: + name: lowcode diff --git a/deployment/deployment/quanxiang_charts/implant/.helmignore b/deployment/charts/quanxiang/charts/faas/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/implant/.helmignore rename to deployment/charts/quanxiang/charts/faas/.helmignore diff --git a/deployment/deployment/quanxiang_charts/faas/Chart.yaml b/deployment/charts/quanxiang/charts/faas/Chart.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/faas/Chart.yaml rename to deployment/charts/quanxiang/charts/faas/Chart.yaml diff --git a/deployment/deployment/quanxiang_charts/faas/subscribe_faas.yaml b/deployment/charts/quanxiang/charts/faas/subscribe_faas.yaml similarity index 80% rename from deployment/deployment/quanxiang_charts/faas/subscribe_faas.yaml rename to deployment/charts/quanxiang/charts/faas/subscribe_faas.yaml index 7915728..29579b1 100644 --- a/deployment/deployment/quanxiang_charts/faas/subscribe_faas.yaml +++ b/deployment/charts/quanxiang/charts/faas/subscribe_faas.yaml @@ -2,6 +2,7 @@ apiVersion: dapr.io/v1alpha1 kind: Subscription metadata: name: faas-dapr + namespace: {{ .Release.Namespace }} spec: topic: lowcode.faas route: /event diff --git a/deployment/deployment/quanxiang_charts/faas/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/faas/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/faas/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/faas/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/faas/templates/configmap.yaml b/deployment/charts/quanxiang/charts/faas/templates/configmap.yaml similarity index 86% rename from deployment/deployment/quanxiang_charts/faas/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/faas/templates/configmap.yaml index c5ead91..fd7303f 100644 --- a/deployment/deployment/quanxiang_charts/faas/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/faas/templates/configmap.yaml @@ -2,7 +2,7 @@ kind: ConfigMap apiVersion: v1 metadata: name: faas - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} data: config.yml: |+ # port 端口 @@ -33,12 +33,11 @@ data: # -------------------- mysql -------------------- mysql: - db: faas - host: {{ .Values.config.mysql.host }} - user: {{ .Values.config.mysql.user }} - password: {{ .Values.config.mysql.password }} - log: {{ .Values.config.mysql.log }} - + db: {{ .Values.mysql.db }} + host: {{ .Values.mysql.host }} + user: {{ .Values.mysql.user }} + password: {{ .Values.mysql.password }} + log: {{ .Values.mysql.log }} # ------------------------ k8s -------------------- k8s: @@ -52,20 +51,20 @@ data: # ---------- redis ---------- redis: - {{- with .Values.config.redis.addrs }} + {{- with .Values.redis.addrs }} addrs: {{- toYaml . | nindent 8 }} {{- end }} - username: {{ .Values.config.redis.username }} - password: {{ .Values.config.redis.password }} + username: {{ .Values.redis.username }} + password: {{ .Values.redis.password }} # -------------------- elastic -------------------- elastic: - {{- with .Values.config.elastic.host }} + {{- with.Values.elastic.host }} host: {{- toYaml . | nindent 8 }} {{- end }} - log: {{ .Values.config.elastic.log }} + log: {{ .Values.elastic.log }} # ---------- graph ---------- graph: runs: @@ -84,7 +83,7 @@ data: - step-results build-images: - go1.16: docker.io/quanxiang/builder-go:v1.16 + go1.16: {{ .Values.goBuildImage }} templates: - full_name: handle.go diff --git a/deployment/deployment/quanxiang_charts/faas/templates/deployment.yaml b/deployment/charts/quanxiang/charts/faas/templates/deployment.yaml similarity index 91% rename from deployment/deployment/quanxiang_charts/faas/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/faas/templates/deployment.yaml index 2830f86..7887294 100644 --- a/deployment/deployment/quanxiang_charts/faas/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/faas/templates/deployment.yaml @@ -2,7 +2,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: faas - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: faas app.kubernetes.io/managed-by: Helm @@ -12,10 +12,10 @@ metadata: annotations: deployment.kubernetes.io/revision: '14' dev.nocalhost/application-name: faas - dev.nocalhost/application-namespace: lowcode + dev.nocalhost/application-namespace: "" dev.nocalhost/dev-mode-count: '0' meta.helm.sh/release-name: faas - meta.helm.sh/release-namespace: lowcode + meta.helm.sh/release-namespace: {{ .Release.Namespace }} nocalhost-dep-ignore: 'true' servicemesh.kubesphere.io/enabled: 'false' spec: @@ -50,7 +50,7 @@ spec: defaultMode: 420 containers: - name: container - image: '{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }}' + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' args: - '--config=/configs/config.yml' ports: diff --git a/deployment/deployment/quanxiang_charts/faas/templates/kafka.yaml b/deployment/charts/quanxiang/charts/faas/templates/kafka.yaml similarity index 81% rename from deployment/deployment/quanxiang_charts/faas/templates/kafka.yaml rename to deployment/charts/quanxiang/charts/faas/templates/kafka.yaml index f77e6f6..490133c 100644 --- a/deployment/deployment/quanxiang_charts/faas/templates/kafka.yaml +++ b/deployment/charts/quanxiang/charts/faas/templates/kafka.yaml @@ -1,6 +1,7 @@ apiVersion: dapr.io/v1alpha1 kind: Component metadata: + namespace: {{ .Release.Namespace }} name: faas-pubsub spec: type: pubsub.kafka @@ -8,7 +9,7 @@ spec: metadata: # Kafka broker connection setting - name: brokers - value: {{ .Values.kafka.value }} + value: {{ join "," .Values.kafka.broker }} - name: authRequired value: "false" - name: authType # Required. diff --git a/deployment/deployment/quanxiang_charts/faas/templates/role.yaml b/deployment/charts/quanxiang/charts/faas/templates/role.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/faas/templates/role.yaml rename to deployment/charts/quanxiang/charts/faas/templates/role.yaml diff --git a/deployment/deployment/quanxiang_charts/faas/templates/role_bidding.yaml b/deployment/charts/quanxiang/charts/faas/templates/role_bidding.yaml similarity index 75% rename from deployment/deployment/quanxiang_charts/faas/templates/role_bidding.yaml rename to deployment/charts/quanxiang/charts/faas/templates/role_bidding.yaml index 0ce9139..ead025c 100644 --- a/deployment/deployment/quanxiang_charts/faas/templates/role_bidding.yaml +++ b/deployment/charts/quanxiang/charts/faas/templates/role_bidding.yaml @@ -2,6 +2,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: qxp-faas + namespace: {{ .Release.Namespace }} roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole @@ -9,4 +10,4 @@ roleRef: subjects: - kind: ServiceAccount name: qxp-faas - namespace: {{ .Values.namespace }} \ No newline at end of file + namespace: {{ .Release.Namespace }} \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/faas/templates/service.yaml b/deployment/charts/quanxiang/charts/faas/templates/service.yaml similarity index 90% rename from deployment/deployment/quanxiang_charts/faas/templates/service.yaml rename to deployment/charts/quanxiang/charts/faas/templates/service.yaml index b51e741..04f7c4d 100644 --- a/deployment/deployment/quanxiang_charts/faas/templates/service.yaml +++ b/deployment/charts/quanxiang/charts/faas/templates/service.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: faas - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: faas spec: diff --git a/deployment/deployment/quanxiang_charts/faas/templates/serviceaccount.yaml b/deployment/charts/quanxiang/charts/faas/templates/serviceaccount.yaml similarity index 77% rename from deployment/deployment/quanxiang_charts/faas/templates/serviceaccount.yaml rename to deployment/charts/quanxiang/charts/faas/templates/serviceaccount.yaml index c94d95d..001a6ab 100644 --- a/deployment/deployment/quanxiang_charts/faas/templates/serviceaccount.yaml +++ b/deployment/charts/quanxiang/charts/faas/templates/serviceaccount.yaml @@ -3,6 +3,6 @@ apiVersion: v1 kind: ServiceAccount metadata: name: qxp-faas - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} secrets: - name: qxp-faas-token-txxtn diff --git a/deployment/deployment/quanxiang_charts/faas/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/faas/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/faas/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/faas/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/faas/values.yaml b/deployment/charts/quanxiang/charts/faas/values.yaml new file mode 100644 index 0000000..b9035ec --- /dev/null +++ b/deployment/charts/quanxiang/charts/faas/values.yaml @@ -0,0 +1,20 @@ +image: + repository: docker.io/quanxiang/faas + tag: v2.0.0 +namespace: "" +imagePullSecrets: "" +goBuildImage: docker.io/quanxiang/builder-go:v1.16 +mysql: {} + +redis: {} +kafka: {} +elastic: {} + +service: + type: ClusterIP + port: 80 + rpcPort: 0 +app: + kubernetes: + io: + name: lowcode \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/fileserver/.helmignore b/deployment/charts/quanxiang/charts/fileserver/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/fileserver/.helmignore rename to deployment/charts/quanxiang/charts/fileserver/.helmignore diff --git a/deployment/charts/quanxiang/charts/fileserver/Chart.yaml b/deployment/charts/quanxiang/charts/fileserver/Chart.yaml new file mode 100644 index 0000000..2f263dd --- /dev/null +++ b/deployment/charts/quanxiang/charts/fileserver/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: fileserver +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/deployment/deployment/quanxiang_charts/fileserver/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/fileserver/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/fileserver/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/fileserver/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/fileserver/templates/configmap.yaml b/deployment/charts/quanxiang/charts/fileserver/templates/configmap.yaml similarity index 71% rename from deployment/deployment/quanxiang_charts/fileserver/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/fileserver/templates/configmap.yaml index ea128d3..825a16e 100644 --- a/deployment/deployment/quanxiang_charts/fileserver/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/fileserver/templates/configmap.yaml @@ -2,7 +2,7 @@ kind: ConfigMap apiVersion: v1 metadata: name: fileserver - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} data: config.yml: | @@ -28,11 +28,11 @@ data: # -------------------- mysql -------------------- mysql: - db: {{ .Values.config.mysql.db }} - host: {{ .Values.config.mysql.host }} - user: {{ .Values.config.mysql.user }} - password: {{ .Values.config.mysql.password }} - log: {{ .Values.config.mysql.log }} + db: {{ .Values.mysql.db }} + host: {{ .Values.mysql.host }} + user: {{ .Values.mysql.user }} + password: {{ .Values.mysql.password }} + log: {{ .Values.mysql.log }} # -------------------- maxSize -------------------- # maxSize limit the size of the uploaded file, default 30MB @@ -40,17 +40,17 @@ data: # -------------------- storage -------------------- redis: - {{- with .Values.config.redis.addrs }} + {{- with .Values.redis.addrs }} addrs: {{- toYaml . | nindent 8 }} {{- end }} - username: {{ .Values.config.redis.username }} - password: {{ .Values.config.redis.password }} + username: {{ .Values.redis.username }} + password: {{ .Values.redis.password }} # -------------------- buckets -------------------- buckets: - readable: qxp-static - private: default + readable: {{ .Values.s3.buckets.readable }} + private: {{ .Values.s3.buckets.private }} # -------------------- blob ---------------------- blob: diff --git a/deployment/deployment/quanxiang_charts/fileserver/templates/deployment.yaml b/deployment/charts/quanxiang/charts/fileserver/templates/deployment.yaml similarity index 75% rename from deployment/deployment/quanxiang_charts/fileserver/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/fileserver/templates/deployment.yaml index 54760aa..a81082b 100644 --- a/deployment/deployment/quanxiang_charts/fileserver/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/fileserver/templates/deployment.yaml @@ -2,7 +2,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: fileserver - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: fileserver app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} @@ -39,12 +39,14 @@ spec: defaultMode: 420 containers: - name: container - image: '{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }}' + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' args: - - '--accesskey=Minio' - - '--secretkey=Minio123456' - - '--endpoint=http://fs.{{ .Values.args.endpoint }}' - - '--region=us-east-1' + {{- if eq .Values.storage.type "minio" }} + - '--accesskey={{ .Values.storage.accessKey }}' + - '--secretkey={{ .Values.storage.secretKey }}' + - '--endpoint={{ .Values.storage.endpoint }}' + - '--region={{ .Values.storage.location }}' + {{- end }} ports: - name: fileserver containerPort: 80 @@ -62,12 +64,12 @@ spec: dnsPolicy: ClusterFirst serviceAccountName: default serviceAccount: default - {{- if .Values.args.enabled }} + {{- if .Values.hostAliases.enabled }} hostAliases: - hostnames: - - fs.{{ .Values.domain }} - - default.fs.{{ .Values.domain }} - ip: {{ .Values.args.ip }} + - fs.{{ or .Values.global.domain .Values.domain }} + - {{ .Values.s3.buckets.private }}.fs.{{ or .Values.global.domain .Values.domain }} + ip: {{ .Values.hostAliases.ip }} {{- end }} securityContext: {} imagePullSecrets: diff --git a/deployment/deployment/quanxiang_charts/fileserver/templates/ingress.yaml b/deployment/charts/quanxiang/charts/fileserver/templates/ingress.yaml similarity index 94% rename from deployment/deployment/quanxiang_charts/fileserver/templates/ingress.yaml rename to deployment/charts/quanxiang/charts/fileserver/templates/ingress.yaml index c3dc02c..45c2f42 100644 --- a/deployment/deployment/quanxiang_charts/fileserver/templates/ingress.yaml +++ b/deployment/charts/quanxiang/charts/fileserver/templates/ingress.yaml @@ -2,7 +2,7 @@ kind: Ingress apiVersion: networking.k8s.io/v1 metadata: name: fileserver - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/proxy-body-size: 30m diff --git a/deployment/deployment/quanxiang_charts/fileserver/templates/service.yml b/deployment/charts/quanxiang/charts/fileserver/templates/service.yml similarity index 94% rename from deployment/deployment/quanxiang_charts/fileserver/templates/service.yml rename to deployment/charts/quanxiang/charts/fileserver/templates/service.yml index 3d4f4f1..4396baf 100644 --- a/deployment/deployment/quanxiang_charts/fileserver/templates/service.yml +++ b/deployment/charts/quanxiang/charts/fileserver/templates/service.yml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: fileserver - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: fileserver app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} diff --git a/deployment/deployment/quanxiang_charts/fileserver/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/fileserver/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/fileserver/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/fileserver/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/fileserver/values.yaml b/deployment/charts/quanxiang/charts/fileserver/values.yaml new file mode 100644 index 0000000..2fa022a --- /dev/null +++ b/deployment/charts/quanxiang/charts/fileserver/values.yaml @@ -0,0 +1,43 @@ +image: + repository: docker.io/quanxiang/fileserver + tag: v2.0.0 +namespace: "" +domain: example.com +mysql: {} + +redis: {} + +storage: + #如果global.minio.enabled为true 此处不需要改动,否则请根据您的minio的信息填写 + type: minio + protocol: http + endpendpoint: http://fs.example.com + accessKey: Minio + secretKey: Minio123456 + location: us-east-1 + bucketName: default + +s3: + buckets: + readable: qxp-static + private: default + +hostAliases: + enabled: true + ip: 192.168.0.10 +ingress: + enabled: false + hosts: + - host: '*.fs.example.com' + paths: + - fullName: minio + path: / + svcPort: 9000 +service: + type: ClusterIP + port: 80 + rpcPort: 0 +app: + kubernetes: + io: + name: backend diff --git a/deployment/deployment/quanxiang_charts/flow/.helmignore b/deployment/charts/quanxiang/charts/flow/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/flow/.helmignore rename to deployment/charts/quanxiang/charts/flow/.helmignore diff --git a/deployment/deployment/quanxiang_charts/flow/0.6.2.sql b/deployment/charts/quanxiang/charts/flow/0.6.2.sql similarity index 100% rename from deployment/deployment/quanxiang_charts/flow/0.6.2.sql rename to deployment/charts/quanxiang/charts/flow/0.6.2.sql diff --git a/deployment/charts/quanxiang/charts/flow/Chart.yaml b/deployment/charts/quanxiang/charts/flow/Chart.yaml new file mode 100644 index 0000000..82f694a --- /dev/null +++ b/deployment/charts/quanxiang/charts/flow/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: flow +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/deployment/deployment/quanxiang_charts/flow/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/flow/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/flow/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/flow/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/flow/templates/configmap.yaml b/deployment/charts/quanxiang/charts/flow/templates/configmap.yaml similarity index 78% rename from deployment/deployment/quanxiang_charts/flow/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/flow/templates/configmap.yaml index 4cbb974..1565b7d 100644 --- a/deployment/deployment/quanxiang_charts/flow/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/flow/templates/configmap.yaml @@ -14,13 +14,11 @@ data: #-------------------mysql配置--------------------- mysql: - db: {{ .Values.config.mysql.db }} - host: {{ .Values.config.mysql.host }} - user: {{ .Values.config.mysql.user }} - password: {{ .Values.config.mysql.password }} - log: {{ .Values.config.mysql.log }} - - + db: {{ .Values.mysql.db }} + host: {{ .Values.mysql.host }} + user: {{ .Values.mysql.user }} + password: {{ .Values.mysql.password }} + log: {{ or .Values.mysql.log .Values.mysql.log }} # -------------------- log -------------------- # comply with zap log specification @@ -42,16 +40,16 @@ data: #-------------------redis配置----------------- redis: - {{- with .Values.config.redis.addrs }} + {{- with .Values.redis.addrs }} addrs: {{- toYaml . | nindent 8 }} {{- end }} - username: {{ .Values.config.redis.username }} - password: {{ .Values.config.redis.password }} + username: {{ .Values.redis.username }} + password: {{ .Values.redis.password }} # -------------------- kafka -------------------- kafka: - {{- with .Values.config.kafka.broker }} + {{- with .Values.kafka.broker }} broker: {{- toYaml . | nindent 8 }} {{- end }} diff --git a/deployment/deployment/quanxiang_charts/flow/templates/deployment.yaml b/deployment/charts/quanxiang/charts/flow/templates/deployment.yaml similarity index 92% rename from deployment/deployment/quanxiang_charts/flow/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/flow/templates/deployment.yaml index 1639c0c..f3b3ff7 100644 --- a/deployment/deployment/quanxiang_charts/flow/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/flow/templates/deployment.yaml @@ -2,7 +2,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: flow - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: flow app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} @@ -41,8 +41,8 @@ spec: name: flow defaultMode: 420 containers: - - name: container - image: '{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }}' + - name: flow + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' ports: - name: flow containerPort: 8081 diff --git a/deployment/deployment/quanxiang_charts/flow/templates/service.yaml b/deployment/charts/quanxiang/charts/flow/templates/service.yaml similarity index 95% rename from deployment/deployment/quanxiang_charts/flow/templates/service.yaml rename to deployment/charts/quanxiang/charts/flow/templates/service.yaml index 2362952..93beb36 100644 --- a/deployment/deployment/quanxiang_charts/flow/templates/service.yaml +++ b/deployment/charts/quanxiang/charts/flow/templates/service.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: flow - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: flow app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} diff --git a/deployment/deployment/quanxiang_charts/flow/templates/subscription-flow.yaml b/deployment/charts/quanxiang/charts/flow/templates/subscription-flow.yaml similarity index 80% rename from deployment/deployment/quanxiang_charts/flow/templates/subscription-flow.yaml rename to deployment/charts/quanxiang/charts/flow/templates/subscription-flow.yaml index cfc954e..0db13a5 100644 --- a/deployment/deployment/quanxiang_charts/flow/templates/subscription-flow.yaml +++ b/deployment/charts/quanxiang/charts/flow/templates/subscription-flow.yaml @@ -2,7 +2,7 @@ apiVersion: dapr.io/v1alpha1 kind: Subscription metadata: name: form-flow - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} spec: topic: form.Flow route: /send diff --git a/deployment/deployment/quanxiang_charts/flow/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/flow/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/flow/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/flow/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/flow/values.yaml b/deployment/charts/quanxiang/charts/flow/values.yaml new file mode 100644 index 0000000..b31eeb4 --- /dev/null +++ b/deployment/charts/quanxiang/charts/flow/values.yaml @@ -0,0 +1,22 @@ +image: + repository: docker.io/quanxiang/flow + tag: v2.0.0 +namespace: "" +imagePullSecrets: "" +service: + type: ClusterIP + port: 80 + rpcPort: 9081 +mysql: {} +redis: {} + +kafka: + broker: + - kafka:9092 + +app: + kubernetes: + io: + name: backend + + diff --git a/deployment/charts/quanxiang/charts/fluent-bit-2.10.3.tgz b/deployment/charts/quanxiang/charts/fluent-bit-2.10.3.tgz new file mode 100644 index 0000000000000000000000000000000000000000..4cd788e8bac8f84f0984fa094c104a76cc1622cb GIT binary patch literal 14321 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 literal 0 HcmV?d00001 diff --git a/deployment/deployment/quanxiang_charts/form/.helmignore b/deployment/charts/quanxiang/charts/form/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/form/.helmignore rename to deployment/charts/quanxiang/charts/form/.helmignore diff --git a/deployment/charts/quanxiang/charts/form/Chart.yaml b/deployment/charts/quanxiang/charts/form/Chart.yaml new file mode 100644 index 0000000..c29b381 --- /dev/null +++ b/deployment/charts/quanxiang/charts/form/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: form +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/deployment/deployment/quanxiang_charts/form/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/form/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/form/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/form/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/form/templates/configmap.yaml b/deployment/charts/quanxiang/charts/form/templates/configmap.yaml similarity index 67% rename from deployment/deployment/quanxiang_charts/form/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/form/templates/configmap.yaml index 6d16c6a..fbfeeca 100644 --- a/deployment/deployment/quanxiang_charts/form/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/form/templates/configmap.yaml @@ -2,7 +2,7 @@ kind: ConfigMap apiVersion: v1 metadata: name: form - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} data: config.yml: |- @@ -30,11 +30,11 @@ data: # -------------------- mysql -------------------- mysql: - db: form - host: {{ .Values.config.mysql.host }} - user: {{ .Values.config.mysql.user }} - password: {{ .Values.config.mysql.password }} - log: {{ .Values.config.mysql.log }} + db: {{ .Values.mysql.db }} + host: {{ .Values.mysql.host }} + user: {{ .Values.mysql.user }} + password: {{ .Values.mysql.password }} + log: {{ .Values.mysql.log }} # -------------------- internalNet -------------------- internalNet: timeout: 20 @@ -43,23 +43,13 @@ data: pubSubName : form-pubsub # -------------------- service -------------------- redis: - {{- with .Values.config.redis.addrs }} + {{- with .Values.redis.addrs }} addrs: {{- toYaml . | nindent 8 }} {{- end }} - username: {{ .Values.config.redis.username }} - password: {{ .Values.config.redis.password }} - # -------------------- mongo --------------------**********洗数据要写真正的ip - mongo: - hosts: - - mon:27017 - direct: - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: qxp - password: ithdVMuaU7r - passwordSet: false + username: {{ .Values.redis.username }} + password: {{ .Values.redis.password }} + dapr: pubSubName : form-pubsub topicFlow: form.Flow @@ -70,9 +60,9 @@ data: polyInner: "http://polyapi:9090" structor: "localhost:8081" db_database: structor - db_host: '{{ .Values.mongo_host }}' - db_password: {{ .Values.config.mongo.credential.password }} - db_user_name: {{ .Values.config.mongo.credential.username }} + db_host: '{{ .Values.mongo.hosts }}' + db_password: {{ .Values.mongo.credential.password }} + db_user_name: {{ .Values.mongo.credential.username }} permit.yml: |+ # port 端口 port: :40001 @@ -111,9 +101,9 @@ data: redis: - {{- with .Values.config.redis.addrs }} + {{- with .Values.redis.addrs }} addrs: {{- toYaml . | nindent 8 }} {{- end }} - username: {{ .Values.config.redis.username }} - password: {{ .Values.config.redis.password }} \ No newline at end of file + username: {{ .Values.redis.username }} + password: {{ .Values.redis.password }} \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/form/templates/deployment.yaml b/deployment/charts/quanxiang/charts/form/templates/deployment.yaml similarity index 92% rename from deployment/deployment/quanxiang_charts/form/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/form/templates/deployment.yaml index 51299dd..42deaed 100644 --- a/deployment/deployment/quanxiang_charts/form/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/form/templates/deployment.yaml @@ -2,7 +2,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: form - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: form app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} @@ -42,7 +42,7 @@ spec: defaultMode: 420 containers: - name: permit - image: '{{ .Values.image.repo }}/permit:{{ .Values.image.tag }}' + image: '{{ .Values.images.permit.repository }}:{{ .Values.images.permit.tag }}' command: - ./cmd/permit args: @@ -59,8 +59,8 @@ spec: terminationMessagePath: /dev/termination-log terminationMessagePolicy: File imagePullPolicy: Always - - name: container - image: '{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }}' + - name: form + image: '{{ .Values.images.form.repository }}:{{ .Values.images.form.tag }}' command: - ./cmd/form args: @@ -81,7 +81,7 @@ spec: terminationMessagePolicy: File imagePullPolicy: IfNotPresent - name: structor - image: '{{ .Values.image.repo }}/structor:{{ .Values.image.tag }}' + image: '{{ .Values.images.structor.repository }}:{{ .Values.images.structor.tag }}' command: - ./cmd/structor args: diff --git a/deployment/deployment/quanxiang_charts/form/templates/pub_sub_kafka.yml b/deployment/charts/quanxiang/charts/form/templates/pub_sub_kafka.yml similarity index 81% rename from deployment/deployment/quanxiang_charts/form/templates/pub_sub_kafka.yml rename to deployment/charts/quanxiang/charts/form/templates/pub_sub_kafka.yml index af44f85..7d243fb 100644 --- a/deployment/deployment/quanxiang_charts/form/templates/pub_sub_kafka.yml +++ b/deployment/charts/quanxiang/charts/form/templates/pub_sub_kafka.yml @@ -2,14 +2,14 @@ apiVersion: dapr.io/v1alpha1 kind: Component metadata: name: form-pubsub - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} spec: type: pubsub.kafka version: v1 metadata: # Kafka broker connection setting - name: brokers - value: {{ .Values.kafka.value }} + value: {{ join "," .Values.kafka.broker }} - name: authRequired value: "false" - name: authType # Required. diff --git a/deployment/deployment/quanxiang_charts/form/templates/service.yaml b/deployment/charts/quanxiang/charts/form/templates/service.yaml similarity index 94% rename from deployment/deployment/quanxiang_charts/form/templates/service.yaml rename to deployment/charts/quanxiang/charts/form/templates/service.yaml index a880ebb..a4bce5b 100644 --- a/deployment/deployment/quanxiang_charts/form/templates/service.yaml +++ b/deployment/charts/quanxiang/charts/form/templates/service.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: form - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: form app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} diff --git a/deployment/deployment/quanxiang_charts/form/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/form/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/form/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/form/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/form/values.yaml b/deployment/charts/quanxiang/charts/form/values.yaml new file mode 100644 index 0000000..27a96e5 --- /dev/null +++ b/deployment/charts/quanxiang/charts/form/values.yaml @@ -0,0 +1,37 @@ +images: + permit: + repository: docker.io/quanxiang/permit + tag: v2.0.0 + structor: + repository: docker.io/quanxiang/structor + tag: v2.0.0 + form: + repository: docker.io/quanxiang/form + tag: v2.0.0 +imagePullSecrets: "" +namespace: "" +mysql: {} +redis: {} +kafka: + broker: + - kafka:9092 +mongo: + hosts: + - mongodb:27017 + direct: false + credential: + authMechanism: SCRAM-SHA-1 + authSource: admin + username: root + password: qxp1234 + passwordSet: false + +service: + type: ClusterIP + port: 80 + rpcPort: 8080 + +app: + kubernetes: + io: + name: backend diff --git a/deployment/deployment/quanxiang_charts/goalie/.helmignore b/deployment/charts/quanxiang/charts/goalie/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/goalie/.helmignore rename to deployment/charts/quanxiang/charts/goalie/.helmignore diff --git a/deployment/charts/quanxiang/charts/goalie/Chart.yaml b/deployment/charts/quanxiang/charts/goalie/Chart.yaml new file mode 100644 index 0000000..d8618ea --- /dev/null +++ b/deployment/charts/quanxiang/charts/goalie/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: goalie +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/deployment/deployment/quanxiang_charts/goalie/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/goalie/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/goalie/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/goalie/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/goalie/templates/configmap.yaml b/deployment/charts/quanxiang/charts/goalie/templates/configmap.yaml similarity index 63% rename from deployment/deployment/quanxiang_charts/goalie/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/goalie/templates/configmap.yaml index 16228b7..67f321b 100644 --- a/deployment/deployment/quanxiang_charts/goalie/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/goalie/templates/configmap.yaml @@ -2,9 +2,7 @@ kind: ConfigMap apiVersion: v1 metadata: name: goalie - namespace: {{ .Values.namespace }} - annotations: - kubesphere.io/alias-name: lowcode-goalie + namespace: {{ .Release.Namespace }} data: config.yml: |- @@ -36,16 +34,16 @@ data: # -------------------- mysql -------------------- mysql: - db: {{ .Values.config.mysql.db }} - host: {{ .Values.config.mysql.host }} - user: {{ .Values.config.mysql.user }} - password: {{ .Values.config.mysql.password }} - log: {{ .Values.config.mysql.log }} + db: {{ .Values.mysql.db }} + host: {{ .Values.mysql.host }} + user: {{ .Values.mysql.user }} + password: {{ .Values.mysql.password }} + log: {{ .Values.mysql.log }} redis: - {{- with .Values.config.redis.addrs }} + {{- with .Values.redis.addrs }} addrs: {{- toYaml . | nindent 8 }} {{- end }} - username: {{ .Values.config.redis.username }} - password: {{ .Values.config.redis.password }} \ No newline at end of file + username: {{ .Values.redis.username }} + password: {{ .Values.redis.password }} \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/goalie/templates/deployment.yaml b/deployment/charts/quanxiang/charts/goalie/templates/deployment.yaml similarity index 92% rename from deployment/deployment/quanxiang_charts/goalie/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/goalie/templates/deployment.yaml index 17a7799..155d94e 100644 --- a/deployment/deployment/quanxiang_charts/goalie/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/goalie/templates/deployment.yaml @@ -2,7 +2,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: goalie - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: goalie app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} @@ -38,8 +38,8 @@ spec: name: goalie defaultMode: 420 containers: - - name: container - image: '{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }}' + - name: goalie + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' ports: - name: goalie containerPort: 80 diff --git a/deployment/deployment/quanxiang_charts/goalie/templates/service.yaml b/deployment/charts/quanxiang/charts/goalie/templates/service.yaml similarity index 94% rename from deployment/deployment/quanxiang_charts/goalie/templates/service.yaml rename to deployment/charts/quanxiang/charts/goalie/templates/service.yaml index 502c87c..d09fd21 100644 --- a/deployment/deployment/quanxiang_charts/goalie/templates/service.yaml +++ b/deployment/charts/quanxiang/charts/goalie/templates/service.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: goalie - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: goalie app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} diff --git a/deployment/deployment/quanxiang_charts/goalie/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/goalie/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/goalie/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/goalie/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/goalie/values.yaml b/deployment/charts/quanxiang/charts/goalie/values.yaml new file mode 100644 index 0000000..c060ae0 --- /dev/null +++ b/deployment/charts/quanxiang/charts/goalie/values.yaml @@ -0,0 +1,18 @@ +image: + repository: docker.io/quanxiang/goalie + tag: v2.0.0 +namespace: "" +imagePullSecrets: "" +mysql: {} +redis: {} + +service: + type: ClusterIP + port: 80 + rpcPort: 0 + +app: + kubernetes: + io: + name: backend + diff --git a/deployment/deployment/quanxiang_charts/warden/.helmignore b/deployment/charts/quanxiang/charts/implant/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/warden/.helmignore rename to deployment/charts/quanxiang/charts/implant/.helmignore diff --git a/deployment/deployment/quanxiang_charts/implant/Chart.yaml b/deployment/charts/quanxiang/charts/implant/Chart.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/implant/Chart.yaml rename to deployment/charts/quanxiang/charts/implant/Chart.yaml diff --git a/deployment/deployment/quanxiang_charts/implant/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/implant/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/implant/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/implant/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/implant/templates/deployment.yaml b/deployment/charts/quanxiang/charts/implant/templates/deployment.yaml similarity index 83% rename from deployment/deployment/quanxiang_charts/implant/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/implant/templates/deployment.yaml index 5aa9b6c..84145c6 100644 --- a/deployment/deployment/quanxiang_charts/implant/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/implant/templates/deployment.yaml @@ -2,13 +2,13 @@ kind: Deployment apiVersion: apps/v1 metadata: name: implant - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: implant annotations: deployment.kubernetes.io/revision: '3' meta.helm.sh/release-name: implant - meta.helm.sh/release-namespace: {{ .Values.namespace }} + meta.helm.sh/release-namespace: {{ .Release.Namespace }} spec: replicas: 3 selector: @@ -25,7 +25,7 @@ spec: spec: containers: - name: implant - image: '{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }}' + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' command: - /ko-app/main.go - '-fn-namespace' @@ -44,7 +44,8 @@ spec: serviceAccountName: implantsa serviceAccount: implantsa securityContext: {} - imagePullSecrets: [] + imagePullSecrets: + - name: {{ .Values.imagePullSecrets }} schedulerName: default-scheduler strategy: type: RollingUpdate diff --git a/deployment/deployment/quanxiang_charts/implant/templates/faas-pubsub.yaml b/deployment/charts/quanxiang/charts/implant/templates/faas-pubsub.yaml similarity index 82% rename from deployment/deployment/quanxiang_charts/implant/templates/faas-pubsub.yaml rename to deployment/charts/quanxiang/charts/implant/templates/faas-pubsub.yaml index d27a094..226c58f 100644 --- a/deployment/deployment/quanxiang_charts/implant/templates/faas-pubsub.yaml +++ b/deployment/charts/quanxiang/charts/implant/templates/faas-pubsub.yaml @@ -2,7 +2,7 @@ apiVersion: dapr.io/v2alpha1 kind: Subscription metadata: name: faas-dapr - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} scopes: - faas-dapr spec: diff --git a/deployment/deployment/quanxiang_charts/implant/templates/role.yaml b/deployment/charts/quanxiang/charts/implant/templates/role.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/implant/templates/role.yaml rename to deployment/charts/quanxiang/charts/implant/templates/role.yaml diff --git a/deployment/deployment/quanxiang_charts/implant/templates/role_bidding.yaml b/deployment/charts/quanxiang/charts/implant/templates/role_bidding.yaml similarity index 85% rename from deployment/deployment/quanxiang_charts/implant/templates/role_bidding.yaml rename to deployment/charts/quanxiang/charts/implant/templates/role_bidding.yaml index a438421..5044d07 100644 --- a/deployment/deployment/quanxiang_charts/implant/templates/role_bidding.yaml +++ b/deployment/charts/quanxiang/charts/implant/templates/role_bidding.yaml @@ -9,4 +9,4 @@ roleRef: subjects: - kind: ServiceAccount name: implantsa - namespace: {{ .Values.namespace }} \ No newline at end of file + namespace: {{ .Release.Namespace }} \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/implant/templates/service.yaml b/deployment/charts/quanxiang/charts/implant/templates/service.yaml similarity index 94% rename from deployment/deployment/quanxiang_charts/implant/templates/service.yaml rename to deployment/charts/quanxiang/charts/implant/templates/service.yaml index f714f31..677a692 100644 --- a/deployment/deployment/quanxiang_charts/implant/templates/service.yaml +++ b/deployment/charts/quanxiang/charts/implant/templates/service.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: implant - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: implant app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} diff --git a/deployment/deployment/quanxiang_charts/implant/templates/serviceaccount.yaml b/deployment/charts/quanxiang/charts/implant/templates/serviceaccount.yaml similarity index 73% rename from deployment/deployment/quanxiang_charts/implant/templates/serviceaccount.yaml rename to deployment/charts/quanxiang/charts/implant/templates/serviceaccount.yaml index afaa340..8cbd872 100644 --- a/deployment/deployment/quanxiang_charts/implant/templates/serviceaccount.yaml +++ b/deployment/charts/quanxiang/charts/implant/templates/serviceaccount.yaml @@ -2,6 +2,6 @@ apiVersion: v1 kind: ServiceAccount metadata: name: implantsa - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} secrets: - name: implantsa-token-jsqqv diff --git a/deployment/deployment/quanxiang_charts/implant/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/implant/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/implant/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/implant/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/implant/values.yaml b/deployment/charts/quanxiang/charts/implant/values.yaml new file mode 100644 index 0000000..951c257 --- /dev/null +++ b/deployment/charts/quanxiang/charts/implant/values.yaml @@ -0,0 +1,22 @@ +# Default values for implant. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 3 + +image: + repository: docker.io/quanxiang/implant + tag: v2.0.0 + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + +namespace: "" +imagePullSecrets: "" +service: + type: ClusterIP + port: 80 + +app: + kubernetes: + io: + name: lowcode \ No newline at end of file diff --git a/deployment/charts/quanxiang/charts/kafka-20.0.2.tgz b/deployment/charts/quanxiang/charts/kafka-20.0.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..f1926f2a95165655fa1dad68e7ac2d61e1bbdf21 GIT binary patch literal 115196 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Ξ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

NL?zWdszDHpB$WV3S-4n4Ug_RA%+z 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 - - # ** THIS IS AN AUTO-GENERATED FILE ** - - # - - - # Default Kibana configuration for docker target - - server.name: kibana - - server.host: "0" - - #elasticsearch.hosts: - - elasticsearch.hosts: [ "http://192.168.208.23:9200","http://192.168.208.24:9200","http://192.168.208.25:9200" ] - - #xpack.monitoring.ui.container.elasticsearch.enabled: true diff --git a/deployment/deployment/kibana/templates/deployment.yaml b/deployment/deployment/kibana/templates/deployment.yaml deleted file mode 100644 index 1204141..0000000 --- a/deployment/deployment/kibana/templates/deployment.yaml +++ /dev/null @@ -1,57 +0,0 @@ -kind: Deployment -apiVersion: apps/v1 -metadata: - name: kibana - namespace: {{ .Values.namespace }} - labels: - app: kibana - annotations: - deployment.kubernetes.io/revision: '1' - kubesphere.io/creator: admin -spec: - replicas: 1 - selector: - matchLabels: - app: kibana - template: - metadata: - creationTimestamp: null - labels: - app: kibana - annotations: - logging.kubesphere.io/logsidecar-config: '{}' - spec: - volumes: - - name: volume-zuhjax - configMap: - name: kibana - defaultMode: 420 - containers: - - name: container-q54rb6 - image: 'kibana:7.16.1' - ports: - - name: http-5601 - containerPort: 5601 - protocol: TCP - resources: {} - volumeMounts: - - name: volume-zuhjax - readOnly: true - mountPath: /usr/share/kibana/config - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - imagePullPolicy: IfNotPresent - restartPolicy: Always - terminationGracePeriodSeconds: 30 - dnsPolicy: ClusterFirst - serviceAccountName: default - serviceAccount: default - securityContext: {} - schedulerName: default-scheduler - strategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 25% - maxSurge: 25% - revisionHistoryLimit: 10 - progressDeadlineSeconds: 600 diff --git a/deployment/deployment/kibana/templates/service.yaml b/deployment/deployment/kibana/templates/service.yaml deleted file mode 100644 index dab2141..0000000 --- a/deployment/deployment/kibana/templates/service.yaml +++ /dev/null @@ -1,22 +0,0 @@ -kind: Service -apiVersion: v1 -metadata: - name: kibana - namespace: {{ .Values.namespace }} - labels: - app: kibana - annotations: - kubesphere.io/creator: admin -spec: - ports: - - name: http-5601 - protocol: TCP - port: 5601 - targetPort: 5601 - selector: - app: kibana - type: ClusterIP - sessionAffinity: None - ipFamilies: - - IPv4 - ipFamilyPolicy: SingleStack diff --git a/deployment/deployment/kibana/values.yaml b/deployment/deployment/kibana/values.yaml deleted file mode 100644 index 727d001..0000000 --- a/deployment/deployment/kibana/values.yaml +++ /dev/null @@ -1,2 +0,0 @@ -namespace: "" -#images: ramencloud/kibana-oss:6.8.21/daduryi/kibana-oss-7.2.0 \ No newline at end of file diff --git a/deployment/deployment/middleware_deployment/dapr/templates/NOTES.txt b/deployment/deployment/middleware_deployment/dapr/templates/NOTES.txt deleted file mode 100644 index b28e23b..0000000 --- a/deployment/deployment/middleware_deployment/dapr/templates/NOTES.txt +++ /dev/null @@ -1,9 +0,0 @@ -Thank you for installing Dapr: High-performance, lightweight serverless runtime for cloud and edge - -Your release is named {{ .Release.Name }}. - -To get started with Dapr, we recommend using our quickstarts: -https://github.com/dapr/quickstarts - -For more information on running Dapr, visit: -https://dapr.io diff --git a/deployment/deployment/middleware_deployment/kafka/Chart.yaml b/deployment/deployment/middleware_deployment/kafka/Chart.yaml deleted file mode 100755 index abb388b..0000000 --- a/deployment/deployment/middleware_deployment/kafka/Chart.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: v1 -description: DEPRECATED Apache Kafka is publish-subscribe messaging rethought as a distributed - commit log. -name: kafka -version: 0.21.5 -appVersion: 5.0.1 -keywords: -- kafka -- zookeeper -- kafka statefulset -home: https://kafka.apache.org/ -sources: -- https://github.com/kubernetes/charts/tree/master/incubator/zookeeper -- https://github.com/Yolean/kubernetes-kafka -- https://github.com/confluentinc/cp-docker-images -- https://github.com/apache/kafka -deprecated: true -icon: https://kafka.apache.org/images/logo.png diff --git a/deployment/deployment/middleware_deployment/kafka/README.md b/deployment/deployment/middleware_deployment/kafka/README.md deleted file mode 100644 index cbb2b14..0000000 --- a/deployment/deployment/middleware_deployment/kafka/README.md +++ /dev/null @@ -1,443 +0,0 @@ -# ⚠️ Repo Archive Notice - -As of Nov 13, 2020, charts in this repo will no longer be updated. -For more information, see the Helm Charts [Deprecation and Archive Notice](https://github.com/helm/charts#%EF%B8%8F-deprecation-and-archive-notice), and [Update](https://helm.sh/blog/charts-repo-deprecation/). - -# Apache Kafka Helm Chart - -This is an implementation of Kafka StatefulSet found here: - - * https://github.com/Yolean/kubernetes-kafka - -## DEPRECATION NOTICE - -This chart is deprecated and no longer supported. - -## Pre Requisites: - -* Kubernetes 1.3 with alpha APIs enabled and support for storage classes - -* PV support on underlying infrastructure - -* Requires at least `v2.0.0-beta.1` version of helm to support - dependency management with requirements.yaml - -## StatefulSet Details - -* https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/ - -## StatefulSet Caveats - -* https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#limitations - -## Chart Details - -This chart will do the following: - -* Implement a dynamically scalable kafka cluster using Kubernetes StatefulSets - -* Implement a dynamically scalable zookeeper cluster as another Kubernetes StatefulSet required for the Kafka cluster above - -* Expose Kafka protocol endpoints via NodePort services (optional) - -### Installing the Chart - -To install the chart with the release name `my-kafka` in the default -namespace: - -``` -$ helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator -$ helm install --name my-kafka incubator/kafka -``` - -If using a dedicated namespace(recommended) then make sure the namespace -exists with: - -``` -$ helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator -$ kubectl create ns kafka -$ helm install --name my-kafka --namespace kafka incubator/kafka -``` - -This chart includes a ZooKeeper chart as a dependency to the Kafka -cluster in its `requirement.yaml` by default. The chart can be customized using the -following configurable parameters: - -| Parameter | Description | Default | -|------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------| -| `image` | Kafka Container image name | `confluentinc/cp-kafka` | -| `imageTag` | Kafka Container image tag | `5.0.1` | -| `imagePullPolicy` | Kafka Container pull policy | `IfNotPresent` | -| `replicas` | Kafka Brokers | `3` | -| `component` | Kafka k8s selector key | `kafka` | -| `resources` | Kafka resource requests and limits | `{}` | -| `securityContext` | Kafka containers security context | `{}` | -| `kafkaHeapOptions` | Kafka broker JVM heap options | `-Xmx1G-Xms1G` | -| `logSubPath` | Subpath under `persistence.mountPath` where kafka logs will be placed. | `logs` | -| `schedulerName` | Name of Kubernetes scheduler (other than the default) | `nil` | -| `serviceAccountName` | Name of Kubernetes serviceAccount. Useful when needing to pull images from custom repositories | `nil` | -| `priorityClassName` | Name of Kubernetes Pod PriorityClass. https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass | `nil` | -| `affinity` | Defines affinities and anti-affinities for pods as defined in: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity preferences | `{}` | -| `tolerations` | List of node tolerations for the pods. https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ | `[]` | -| `headless.annotations` | List of annotations for the headless service. https://kubernetes.io/docs/concepts/services-networking/service/#headless-services | `[]` | -| `headless.targetPort` | Target port to be used for the headless service. This is not a required value. | `nil` | -| `headless.port` | Port to be used for the headless service. https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ | `9092` | -| `external.enabled` | If True, exposes Kafka brokers via NodePort (PLAINTEXT by default) | `false` | -| `external.dns.useInternal` | If True, add Annotation for internal DNS service | `false` | -| `external.dns.useExternal` | If True, add Annotation for external DNS service | `true` | -| `external.servicePort` | TCP port configured at external services (one per pod) to relay from NodePort to the external listener port. | '19092' | -| `external.firstListenerPort` | TCP port which is added pod index number to arrive at the port used for NodePort and external listener port. | '31090' | -| `external.domain` | Domain in which to advertise Kafka external listeners. | `cluster.local` | -| `external.type` | Service Type. | `NodePort` | -| `external.distinct` | Distinct DNS entries for each created A record. | `false` | -| `external.annotations` | Additional annotations for the external service. | `{}` | -| `external.labels` | Additional labels for the external service. | `{}` | -| `external.loadBalancerIP` | Add Static IP to the type Load Balancer. Depends on the provider if enabled | `[]` -| `external.loadBalancerSourceRanges` | Add IP ranges that are allowed to access the Load Balancer. | `[]` -| `podAnnotations` | Annotation to be added to Kafka pods | `{}` | -| `podLabels` | Labels to be added to Kafka pods | `{}` | -| `podDisruptionBudget` | Define a Disruption Budget for the Kafka Pods | `{}` | -| `envOverrides` | Add additional Environment Variables in the dictionary format | `{ zookeeper.sasl.enabled: "False" }` | -| `configurationOverrides` | `Kafka ` [configuration setting][brokerconfigs] overrides in the dictionary format | `{ "confluent.support.metrics.enable": false }` | -| `secrets` | Pass any secrets to the kafka pods. Each secret will be passed as an environment variable by default. The secret can also be mounted to a specific path if required. Environment variable names are generated as: `_` (All upper case) | `{}` | -| `additionalPorts` | Additional ports to expose on brokers. Useful when the image exposes metrics (like prometheus, etc.) through a javaagent instead of a sidecar | `{}` | -| `readinessProbe.initialDelaySeconds` | Number of seconds before probe is initiated. | `30` | -| `readinessProbe.periodSeconds` | How often (in seconds) to perform the probe. | `10` | -| `readinessProbe.timeoutSeconds` | Number of seconds after which the probe times out. | `5` | -| `readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed. | `1` | -| `readinessProbe.failureThreshold` | After the probe fails this many times, pod will be marked Unready. | `3` | -| `terminationGracePeriodSeconds` | Wait up to this many seconds for a broker to shut down gracefully, after which it is killed | `60` | -| `updateStrategy` | StatefulSet update strategy to use. | `{ type: "OnDelete" }` | -| `podManagementPolicy` | Start and stop pods in Parallel or OrderedReady (one-by-one.) Can not change after first release. | `OrderedReady` | -| `persistence.enabled` | Use a PVC to persist data | `true` | -| `persistence.size` | Size of data volume | `1Gi` | -| `persistence.mountPath` | Mount path of data volume | `/opt/kafka/data` | -| `persistence.storageClass` | Storage class of backing PVC | `nil` | -| `jmx.configMap.enabled` | Enable the default ConfigMap for JMX | `true` | -| `jmx.configMap.overrideConfig` | Allows config file to be generated by passing values to ConfigMap | `{}` | -| `jmx.configMap.overrideName` | Allows setting the name of the ConfigMap to be used | `""` | -| `jmx.port` | The jmx port which JMX style metrics are exposed (note: these are not scrapeable by Prometheus) | `5555` | -| `jmx.whitelistObjectNames` | Allows setting which JMX objects you want to expose to via JMX stats to JMX Exporter | (see `values.yaml`) | -| `nodeSelector` | Node labels for pod assignment | `{}` | -| `prometheus.jmx.resources` | Allows setting resource limits for jmx sidecar container | `{}` | -| `prometheus.jmx.enabled` | Whether or not to expose JMX metrics to Prometheus | `false` | -| `prometheus.jmx.image` | JMX Exporter container image | `solsson/kafka-prometheus-jmx-exporter@sha256` | -| `prometheus.jmx.imageTag` | JMX Exporter container image tag | `a23062396cd5af1acdf76512632c20ea6be76885dfc20cd9ff40fb23846557e8` | -| `prometheus.jmx.interval` | Interval that Prometheus scrapes JMX metrics when using Prometheus Operator | `10s` | -| `prometheus.jmx.scrapeTimeout` | Timeout that Prometheus scrapes JMX metrics when using Prometheus Operator | `10s` | -| `prometheus.jmx.port` | JMX Exporter Port which exposes metrics in Prometheus format for scraping | `5556` | -| `prometheus.kafka.enabled` | Whether or not to create a separate Kafka exporter | `false` | -| `prometheus.kafka.image` | Kafka Exporter container image | `danielqsj/kafka-exporter` | -| `prometheus.kafka.imageTag` | Kafka Exporter container image tag | `v1.2.0` | -| `prometheus.kafka.interval` | Interval that Prometheus scrapes Kafka metrics when using Prometheus Operator | `10s` | -| `prometheus.kafka.scrapeTimeout` | Timeout that Prometheus scrapes Kafka metrics when using Prometheus Operator | `10s` | -| `prometheus.kafka.port` | Kafka Exporter Port which exposes metrics in Prometheus format for scraping | `9308` | -| `prometheus.kafka.resources` | Allows setting resource limits for kafka-exporter pod | `{}` | -| `prometheus.kafka.affinity` | Defines affinities and anti-affinities for pods as defined in: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity preferences | `{}` | -| `prometheus.kafka.tolerations` | List of node tolerations for the pods. https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ | `[]` | -| `prometheus.operator.enabled` | True if using the Prometheus Operator, False if not | `false` | -| `prometheus.operator.serviceMonitor.namespace` | Namespace in which to install the ServiceMonitor resource. Default to kube-prometheus install. | `monitoring` | -| `prometheus.operator.serviceMonitor.releaseNamespace` | Set namespace to release namespace. Default false | `false` | -| `prometheus.operator.serviceMonitor.selector` | Default to kube-prometheus install (CoreOS recommended), but should be set according to Prometheus install | `{ prometheus: kube-prometheus }` | -| `prometheus.operator.prometheusRule.enabled` | True to create a PrometheusRule resource for Prometheus Operator, False if not | `false` | -| `prometheus.operator.prometheusRule.namespace` | Namespace in which to install the PrometheusRule resource. Default to kube-prometheus install. | `monitoring` | -| `prometheus.operator.prometheusRule.releaseNamespace` | Set namespace to release namespace. Default false | `false` | -| `prometheus.operator.prometheusRule.selector` | Default to kube-prometheus install (CoreOS recommended), but should be set according to Prometheus install | `{ prometheus: kube-prometheus }` | -| `prometheus.operator.prometheusRule.rules` | Define the prometheus rules. See values file for examples | `{}` | -| `configJob.backoffLimit` | Number of retries before considering kafka-config job as failed | `6` | -| `topics` | List of topics to create & configure. Can specify name, partitions, replicationFactor, reassignPartitions, config. See values.yaml | `[]` (Empty list) | -| `testsEnabled` | Enable/disable the chart's tests | `true` | -| `zookeeper.enabled` | If True, installs Zookeeper Chart | `true` | -| `zookeeper.resources` | Zookeeper resource requests and limits | `{}` | -| `zookeeper.env` | Environmental variables provided to Zookeeper Zookeeper | `{ZK_HEAP_SIZE: "1G"}` | -| `zookeeper.storage` | Zookeeper Persistent volume size | `2Gi` | -| `zookeeper.image.PullPolicy` | Zookeeper Container pull policy | `IfNotPresent` | -| `zookeeper.url` | URL of Zookeeper Cluster (unneeded if installing Zookeeper Chart) | `""` | -| `zookeeper.port` | Port of Zookeeper Cluster | `2181` | -| `zookeeper.affinity` | Defines affinities and anti-affinities for pods as defined in: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity preferences | `{}` | -| `zookeeper.nodeSelector` | Node labels for pod assignment | `{}` | - -Specify parameters using `--set key=value[,key=value]` argument to `helm install` - -Alternatively a YAML file that specifies the values for the parameters can be provided like this: - -```bash -$ helm install --name my-kafka -f values.yaml incubator/kafka -``` - -### Connecting to Kafka from inside Kubernetes - -You can connect to Kafka by running a simple pod in the K8s cluster like this with a configuration like this: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: testclient - namespace: kafka -spec: - containers: - - name: kafka - image: solsson/kafka:0.11.0.0 - command: - - sh - - -c - - "exec tail -f /dev/null" -``` - -Once you have the testclient pod above running, you can list all kafka -topics with: - -` kubectl -n kafka exec -ti testclient -- ./bin/kafka-topics.sh --zookeeper -my-release-zookeeper:2181 --list` - -Where `my-release` is the name of your helm release. - -## Extensions - -Kafka has a rich ecosystem, with lots of tools. This sections is intended to compile all of those tools for which a corresponding Helm chart has already been created. - -- [Schema-registry](https://github.com/kubernetes/charts/tree/master/incubator/schema-registry) - A confluent project that provides a serving layer for your metadata. It provides a RESTful interface for storing and retrieving Avro schemas. - -## Connecting to Kafka from outside Kubernetes - -### NodePort External Service Type - -Review and optionally override to enable the example text concerned with external access in `values.yaml`. - -Once configured, you should be able to reach Kafka via NodePorts, one per replica. In kops where private, -topology is enabled, this feature publishes an internal round-robin DNS record using the following naming -scheme. The external access feature of this chart was tested with kops on AWS using flannel networking. -If you wish to enable external access to Kafka running in kops, your security groups will likely need to -be adjusted to allow non-Kubernetes nodes (e.g. bastion) to access the Kafka external listener port range. - -``` -{{ .Release.Name }}.{{ .Values.external.domain }} -``` - -If `external.distinct` is set theses entries will be prefixed with the replica number or broker id. - -``` -{{ .Release.Name }}-.{{ .Values.external.domain }} -``` - -Port numbers for external access used at container and NodePort are unique to each container in the StatefulSet. -Using the default `external.firstListenerPort` number with a `replicas` value of `3`, the following -container and NodePorts will be opened for external access: `31090`, `31091`, `31092`. All of these ports should -be reachable from any host to NodePorts are exposed because Kubernetes routes each NodePort from entry node -to pod/container listening on the same port (e.g. `31091`). - -The `external.servicePort` at each external access service (one such service per pod) is a relay toward -the a `containerPort` with a number matching its respective `NodePort`. The range of NodePorts is set, but -should not actually listen, on all Kafka pods in the StatefulSet. As any given pod will listen only one -such port at a time, setting the range at every Kafka pod is a reasonably safe configuration. - -#### Example values.yml for external service type NodePort -The + lines are with the updated values. -``` - external: -- enabled: false -+ enabled: true - # type can be either NodePort or LoadBalancer - type: NodePort - # annotations: -@@ -170,14 +170,14 @@ configurationOverrides: - ## - ## Setting "advertised.listeners" here appends to "PLAINTEXT://${POD_IP}:9092,", ensure you update the domain - ## If external service type is Nodeport: -- # "advertised.listeners": |- -- # EXTERNAL://kafka.cluster.local:$((31090 + ${KAFKA_BROKER_ID})) -+ "advertised.listeners": |- -+ EXTERNAL://kafka.cluster.local:$((31090 + ${KAFKA_BROKER_ID})) - ## If external service type is LoadBalancer and distinct is true: - # "advertised.listeners": |- - # EXTERNAL://kafka-$((${KAFKA_BROKER_ID})).cluster.local:19092 - ## If external service type is LoadBalancer and distinct is false: - # "advertised.listeners": |- - # EXTERNAL://EXTERNAL://${LOAD_BALANCER_IP}:31090 - ## Uncomment to define the EXTERNAL Listener protocol -- # "listener.security.protocol.map": |- -- # PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT -+ "listener.security.protocol.map": |- -+ PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT - - -$ kafkacat -b kafka.cluster.local:31090 -L -Metadata for all topics (from broker 0: kafka.cluster.local:31090/0): - 3 brokers: - broker 2 at kafka.cluster.local:31092 - broker 1 at kafka.cluster.local:31091 - broker 0 at kafka.cluster.local:31090 - 0 topics: - -$ kafkacat -b kafka.cluster.local:31090 -P -t test1 -p 0 -msg01 from external producer to topic test1 - -$ kafkacat -b kafka.cluster.local:31090 -C -t test1 -p 0 -msg01 from external producer to topic test1 -``` -### LoadBalancer External Service Type - -The load balancer external service type differs from the node port type by routing to the `external.servicePort` specified in the service for each statefulset container (if `external.distinct` is set). If `external.distinct` is false, `external.servicePort` is unused and will be set to the sum of `external.firstListenerPort` and the replica number. It is important to note that `external.firstListenerPort` does not have to be within the configured node port range for the cluster, however a node port will be allocated. - -#### Example values.yml and DNS setup for external service type LoadBalancer with external.distinct: true -The + lines are with the updated values. -``` - external: -- enabled: false -+ enabled: true - # type can be either NodePort or LoadBalancer -- type: NodePort -+ type: LoadBalancer - # annotations: - # service.beta.kubernetes.io/openstack-internal-load-balancer: "true" - dns: -@@ -138,10 +138,10 @@ external: - # If using external service type LoadBalancer and external dns, set distinct to true below. - # This creates an A record for each statefulset pod/broker. You should then map the - # A record of the broker to the EXTERNAL IP given by the LoadBalancer in your DNS server. -- distinct: false -+ distinct: true - servicePort: 19092 - firstListenerPort: 31090 -- domain: cluster.local -+ domain: example.com - loadBalancerIP: [] - init: - image: "lwolf/kubectl_deployer" -@@ -173,11 +173,11 @@ configurationOverrides: - # "advertised.listeners": |- - # EXTERNAL://kafka.cluster.local:$((31090 + ${KAFKA_BROKER_ID})) - ## If external service type is LoadBalancer and distinct is true: -- # "advertised.listeners": |- -- # EXTERNAL://kafka-$((${KAFKA_BROKER_ID})).cluster.local:19092 -+ "advertised.listeners": |- -+ EXTERNAL://kafka-$((${KAFKA_BROKER_ID})).example.com:19092 - ## Uncomment to define the EXTERNAL Listener protocol -- # "listener.security.protocol.map": |- -- # PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT -+ "listener.security.protocol.map": |- -+ PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT - -$ kubectl -n kafka get svc -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kafka ClusterIP 10.39.241.217 9092/TCP 2m39s -kafka-0-external LoadBalancer 10.39.242.45 35.200.238.174 19092:30108/TCP 2m39s -kafka-1-external LoadBalancer 10.39.241.90 35.244.44.162 19092:30582/TCP 2m39s -kafka-2-external LoadBalancer 10.39.243.160 35.200.149.80 19092:30539/TCP 2m39s -kafka-headless ClusterIP None 9092/TCP 2m39s -kafka-zookeeper ClusterIP 10.39.249.70 2181/TCP 2m39s -kafka-zookeeper-headless ClusterIP None 2181/TCP,3888/TCP,2888/TCP 2m39s - -DNS A record entries: -kafka-0.example.com A record 35.200.238.174 TTL 60sec -kafka-1.example.com A record 35.244.44.162 TTL 60sec -kafka-2.example.com A record 35.200.149.80 TTL 60sec - -$ ping kafka-0.example.com -PING kafka-0.example.com (35.200.238.174): 56 data bytes - -$ kafkacat -b kafka-0.example.com:19092 -L -Metadata for all topics (from broker 0: kafka-0.example.com:19092/0): - 3 brokers: - broker 2 at kafka-2.example.com:19092 - broker 1 at kafka-1.example.com:19092 - broker 0 at kafka-0.example.com:19092 - 0 topics: - -$ kafkacat -b kafka-0.example.com:19092 -P -t gkeTest -p 0 -msg02 for topic gkeTest - -$ kafkacat -b kafka-0.example.com:19092 -C -t gkeTest -p 0 -msg02 for topic gkeTest -``` - -#### Example values.yml and DNS setup for external service type LoadBalancer with external.distinct: false -The + lines are with the updated values. -``` - external: -- enabled: false -+ enabled: true - # type can be either NodePort or LoadBalancer -- type: NodePort -+ type: LoadBalancer - # annotations: - # service.beta.kubernetes.io/openstack-internal-load-balancer: "true" - dns: -@@ -138,10 +138,10 @@ external: - distinct: false - servicePort: 19092 - firstListenerPort: 31090 - domain: cluster.local - loadBalancerIP: [35.200.238.174,35.244.44.162,35.200.149.80] - init: - image: "lwolf/kubectl_deployer" -@@ -173,11 +173,11 @@ configurationOverrides: - # "advertised.listeners": |- - # EXTERNAL://kafka.cluster.local:$((31090 + ${KAFKA_BROKER_ID})) - ## If external service type is LoadBalancer and distinct is true: -- # "advertised.listeners": |- -- # EXTERNAL://kafka-$((${KAFKA_BROKER_ID})).cluster.local:19092 -+ "advertised.listeners": |- -+ EXTERNAL://${LOAD_BALANCER_IP}:31090 - ## Uncomment to define the EXTERNAL Listener protocol -- # "listener.security.protocol.map": |- -- # PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT -+ "listener.security.protocol.map": |- -+ PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT - -$ kubectl -n kafka get svc -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kafka ClusterIP 10.39.241.217 9092/TCP 2m39s -kafka-0-external LoadBalancer 10.39.242.45 35.200.238.174 31090:30108/TCP 2m39s -kafka-1-external LoadBalancer 10.39.241.90 35.244.44.162 31090:30582/TCP 2m39s -kafka-2-external LoadBalancer 10.39.243.160 35.200.149.80 31090:30539/TCP 2m39s -kafka-headless ClusterIP None 9092/TCP 2m39s -kafka-zookeeper ClusterIP 10.39.249.70 2181/TCP 2m39s -kafka-zookeeper-headless ClusterIP None 2181/TCP,3888/TCP,2888/TCP 2m39s - -$ kafkacat -b 35.200.238.174:31090 -L -Metadata for all topics (from broker 0: 35.200.238.174:31090/0): - 3 brokers: - broker 2 at 35.200.149.80:31090 - broker 1 at 35.244.44.162:31090 - broker 0 at 35.200.238.174:31090 - 0 topics: - -$ kafkacat -b 35.200.238.174:31090 -P -t gkeTest -p 0 -msg02 for topic gkeTest - -$ kafkacat -b 35.200.238.174:31090 -C -t gkeTest -p 0 -msg02 for topic gkeTest -``` - -## Known Limitations - -* Only supports storage options that have backends for persistent volume claims (tested mostly on AWS) -* KAFKA_PORT will be created as an envvar and brokers will fail to start when there is a service named `kafka` in the same namespace. We work around this be unsetting that envvar `unset KAFKA_PORT`. - -[brokerconfigs]: https://kafka.apache.org/documentation/#brokerconfigs - -## Prometheus Stats - -### Prometheus vs Prometheus Operator - -Standard Prometheus is the default monitoring option for this chart. This chart also supports the CoreOS Prometheus Operator, -which can provide additional functionality like automatically updating Prometheus and Alert Manager configuration. If you are -interested in installing the Prometheus Operator please see the [CoreOS repository](https://github.com/coreos/prometheus-operator/tree/master/helm) for more information or -read through the [CoreOS blog post introducing the Prometheus Operator](https://coreos.com/blog/the-prometheus-operator.html) - -### JMX Exporter - -The majority of Kafka statistics are provided via JMX and are exposed via the [Prometheus JMX Exporter](https://github.com/prometheus/jmx_exporter). - -The JMX Exporter is a general purpose prometheus provider which is intended for use with any Java application. Because of this, it produces a number of statistics which -may not be of interest. To help in reducing these statistics to their relevant components we have created a curated whitelist `whitelistObjectNames` for the JMX exporter. -This whitelist may be modified or removed via the values configuration. - -To accommodate compatibility with the Prometheus metrics, this chart performs transformations of raw JMX metrics. For example, broker names and topics names are incorporated -into the metric name instead of becoming a label. If you are curious to learn more about any default transformations to the chart metrics, please have reference the [configmap template](https://github.com/kubernetes/charts/blob/master/incubator/kafka/templates/jmx-configmap.yaml). - -### Kafka Exporter - -The [Kafka Exporter](https://github.com/danielqsj/kafka_exporter) is a complementary metrics exporter to the JMX Exporter. The Kafka Exporter provides additional statistics on Kafka Consumer Groups. diff --git a/deployment/deployment/middleware_deployment/kafka/templates/NOTES.txt b/deployment/deployment/middleware_deployment/kafka/templates/NOTES.txt deleted file mode 100644 index 5f7b406..0000000 --- a/deployment/deployment/middleware_deployment/kafka/templates/NOTES.txt +++ /dev/null @@ -1,76 +0,0 @@ -### Connecting to Kafka from inside Kubernetes - -You can connect to Kafka by running a simple pod in the K8s cluster like this with a configuration like this: - - apiVersion: v1 - kind: Pod - metadata: - name: testclient - namespace: {{ .Release.Namespace }} - spec: - containers: - - name: kafka - image: {{ .Values.image }}:{{ .Values.imageTag }} - command: - - sh - - -c - - "exec tail -f /dev/null" - -Once you have the testclient pod above running, you can list all kafka -topics with: - - kubectl -n {{ .Release.Namespace }} exec testclient -- ./bin/kafka-topics.sh --zookeeper {{ .Release.Name }}-zookeeper:2181 --list - -To create a new topic: - - kubectl -n {{ .Release.Namespace }} exec testclient -- ./bin/kafka-topics.sh --zookeeper {{ .Release.Name }}-zookeeper:2181 --topic test1 --create --partitions 1 --replication-factor 1 - -To listen for messages on a topic: - - kubectl -n {{ .Release.Namespace }} exec -ti testclient -- ./bin/kafka-console-consumer.sh --bootstrap-server {{ include "kafka.fullname" . }}:9092 --topic test1 --from-beginning - -To stop the listener session above press: Ctrl+C - -To start an interactive message producer session: - kubectl -n {{ .Release.Namespace }} exec -ti testclient -- ./bin/kafka-console-producer.sh --broker-list {{ include "kafka.fullname" . }}-headless:9092 --topic test1 - -To create a message in the above session, simply type the message and press "enter" -To end the producer session try: Ctrl+C - -If you specify "zookeeper.connect" in configurationOverrides, please replace "{{ .Release.Name }}-zookeeper:2181" with the value of "zookeeper.connect", or you will get error. - -{{ if .Values.external.enabled }} -### Connecting to Kafka from outside Kubernetes - -You have enabled the external access feature of this chart. - -**WARNING:** By default this feature allows Kafka clients outside Kubernetes to -connect to Kafka via NodePort(s) in `PLAINTEXT`. - -Please see this chart's README.md for more details and guidance. - -If you wish to connect to Kafka from outside please configure your external Kafka -clients to point at the following brokers. Please allow a few minutes for all -associated resources to become healthy. - {{ $fullName := include "kafka.fullname" . }} - {{- $replicas := .Values.replicas | int }} - {{- $servicePort := .Values.external.servicePort | int}} - {{- $root := . }} - {{- range $i, $e := until $replicas }} - {{- $externalListenerPort := add $root.Values.external.firstListenerPort $i }} - {{- if $root.Values.external.distinct }} -{{ printf "%s-%d.%s:%d" $root.Release.Name $i $root.Values.external.domain $servicePort | indent 2 }} - {{- else }} -{{ printf "%s.%s:%d" $root.Release.Name $root.Values.external.domain $externalListenerPort | indent 2 }} - {{- end }} - {{- end }} -{{- end }} - -{{ if .Values.prometheus.jmx.enabled }} -To view JMX configuration (pull request/updates to improve defaults are encouraged): - {{ if .Values.jmx.configMap.overrideName }} - kubectl -n {{ .Release.Namespace }} describe configmap {{ .Values.jmx.configMap.overrideName }} - {{ else }} - kubectl -n {{ .Release.Namespace }} describe configmap {{ include "kafka.fullname" . }}-metrics - {{- end }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/kafka/templates/_helpers.tpl b/deployment/deployment/middleware_deployment/kafka/templates/_helpers.tpl deleted file mode 100644 index 03bfc0a..0000000 --- a/deployment/deployment/middleware_deployment/kafka/templates/_helpers.tpl +++ /dev/null @@ -1,128 +0,0 @@ -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "kafka.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 "kafka.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 zookeeper name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -*/}} -{{- define "kafka.zookeeper.fullname" -}} -{{- if .Values.zookeeper.fullnameOverride -}} -{{- .Values.zookeeper.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default "zookeeper" .Values.zookeeper.nameOverride -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} - -{{/* -Form the Zookeeper URL. If zookeeper is installed as part of this chart, use k8s service discovery, -else use user-provided URL -*/}} -{{- define "zookeeper.url" }} -{{- $port := .Values.zookeeper.port | toString }} -{{- if .Values.zookeeper.enabled -}} -{{- printf "%s:%s" (include "kafka.zookeeper.fullname" .) $port }} -{{- else -}} -{{- $zookeeperConnect := printf "%s:%s" .Values.zookeeper.url $port }} -{{- $zookeeperConnectOverride := index .Values "configurationOverrides" "zookeeper.connect" }} -{{- default $zookeeperConnect $zookeeperConnectOverride }} -{{- end -}} -{{- end -}} - -{{/* -Derive offsets.topic.replication.factor in following priority order: configurationOverrides, replicas -*/}} -{{- define "kafka.replication.factor" }} -{{- $replicationFactorOverride := index .Values "configurationOverrides" "offsets.topic.replication.factor" }} -{{- default .Values.replicas $replicationFactorOverride }} -{{- end -}} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "kafka.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create unified labels for kafka components -*/}} - -{{- define "kafka.common.matchLabels" -}} -app.kubernetes.io/name: {{ include "kafka.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end -}} - -{{- define "kafka.common.metaLabels" -}} -helm.sh/chart: {{ include "kafka.chart" . }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end -}} - -{{- define "kafka.broker.matchLabels" -}} -app.kubernetes.io/component: kafka-broker -{{ include "kafka.common.matchLabels" . }} -{{- end -}} - -{{- define "kafka.broker.labels" -}} -{{ include "kafka.common.metaLabels" . }} -{{ include "kafka.broker.matchLabels" . }} -{{- end -}} - -{{- define "kafka.config.matchLabels" -}} -app.kubernetes.io/component: kafka-config -{{ include "kafka.common.matchLabels" . }} -{{- end -}} - -{{- define "kafka.config.labels" -}} -{{ include "kafka.common.metaLabels" . }} -{{ include "kafka.config.matchLabels" . }} -{{- end -}} - -{{- define "kafka.monitor.matchLabels" -}} -app.kubernetes.io/component: kafka-monitor -{{ include "kafka.common.matchLabels" . }} -{{- end -}} - -{{- define "kafka.monitor.labels" -}} -{{ include "kafka.common.metaLabels" . }} -{{ include "kafka.monitor.matchLabels" . }} -{{- end -}} - -{{- define "serviceMonitor.namespace" -}} -{{- if .Values.prometheus.operator.serviceMonitor.releaseNamespace -}} -{{ .Release.Namespace }} -{{- else -}} -{{ .Values.prometheus.operator.serviceMonitor.namespace }} -{{- end -}} -{{- end -}} - -{{- define "prometheusRule.namespace" -}} -{{- if .Values.prometheus.operator.prometheusRule.releaseNamespace -}} -{{ .Release.Namespace }} -{{- else -}} -{{ .Values.prometheus.operator.prometheusRule.namespace }} -{{- end -}} -{{- end -}} diff --git a/deployment/deployment/middleware_deployment/kafka/templates/configmap-config.yaml b/deployment/deployment/middleware_deployment/kafka/templates/configmap-config.yaml deleted file mode 100644 index a4bfd9b..0000000 --- a/deployment/deployment/middleware_deployment/kafka/templates/configmap-config.yaml +++ /dev/null @@ -1,79 +0,0 @@ -{{- if .Values.topics -}} -{{- $zk := include "zookeeper.url" . -}} -apiVersion: v1 -kind: ConfigMap -metadata: - labels: - {{- include "kafka.config.labels" . | nindent 4 }} - name: {{ template "kafka.fullname" . }}-config -data: - runtimeConfig.sh: | - #!/bin/bash - set -e - cd /usr/bin - until kafka-configs --zookeeper {{ $zk }} --entity-type topics --describe || (( count++ >= 6 )) - do - echo "Waiting for ZooKeeper..." - sleep 20 - done - - # expected='0,1,2,3,...,n,' - # the trailing comma is significant - expected='{{ until (int .Values.replicas) | join "," | trim }},' - connected_brokers='' - until [[ "$connected_brokers" == "$expected" ]] - do - echo "Waiting for all Kafka brokers to be connected to ZooKeeper..." - connected_brokers=$(zookeeper-shell {{ $zk }} ls /brokers/ids | \ - # brokers formatted as: [ 0, 1, 2 ] - tail -1 | \ - # broker ids separated by newline - grep -o '[0-9]\+' | \ - # they may have connected in a random order - sort | \ - # trim the leading and trailing whitespace - sed 's/ *$//' | \ - # Replace newline with comma - # The result has a trailing comma - tr '\n' ',' - ) - echo "Currently available brokers: $connected_brokers" - echo "Expected brokers: $expected" - sleep 20 - done - - echo "Applying runtime configuration using {{ .Values.image }}:{{ .Values.imageTag }}" - {{- range $n, $topic := .Values.topics }} - {{- if and $topic.partitions $topic.replicationFactor $topic.reassignPartitions }} - cat << EOF > {{ $topic.name }}-increase-replication-factor.json - {"version":1, "partitions":[ - {{- $partitions := (int $topic.partitions) }} - {{- $replicas := (int $topic.replicationFactor) }} - {{- range $i := until $partitions }} - {"topic":"{{ $topic.name }}","partition":{{ $i }},"replicas":[{{- range $j := until $replicas }}{{ $j }}{{- if ne $j (sub $replicas 1) }},{{- end }}{{- end }}]}{{- if ne $i (sub $partitions 1) }},{{- end }} - {{- end }} - ]} - EOF - kafka-reassign-partitions --zookeeper {{ $zk }} --reassignment-json-file {{ $topic.name }}-increase-replication-factor.json --execute - kafka-reassign-partitions --zookeeper {{ $zk }} --reassignment-json-file {{ $topic.name }}-increase-replication-factor.json --verify - {{- else if and $topic.partitions $topic.replicationFactor }} - kafka-topics --zookeeper {{ $zk }} --create --if-not-exists --force --topic {{ $topic.name }} --partitions {{ $topic.partitions }} --replication-factor {{ $topic.replicationFactor }} - {{- else if $topic.partitions }} - kafka-topics --zookeeper {{ $zk }} --alter --force --topic {{ $topic.name }} --partitions {{ $topic.partitions }} || true - {{- end }} - {{- if $topic.defaultConfig }} - kafka-configs --zookeeper {{ $zk }} --entity-type topics --entity-name {{ $topic.name }} --alter --force --delete-config {{ nospace $topic.defaultConfig }} || true - {{- end }} - {{- if $topic.config }} - kafka-configs --zookeeper {{ $zk }} --entity-type topics --entity-name {{ $topic.name }} --alter --force --add-config {{ nospace $topic.config }} - {{- end }} - kafka-configs --zookeeper {{ $zk }} --entity-type topics --entity-name {{ $topic.name }} --describe - {{- if $topic.acls }} - {{- range $a, $acl := $topic.acls }} - {{ if and $acl.user $acl.operations }} - kafka-acls --authorizer-properties zookeeper.connect={{ $zk }} --force --add --allow-principal User:{{ $acl.user }}{{- range $operation := $acl.operations }} --operation {{ $operation }} {{- end }} --topic {{ $topic.name }} {{ $topic.extraParams }} - {{- end }} - {{- end }} - {{- end }} - {{- end }} -{{- end -}} diff --git a/deployment/deployment/middleware_deployment/kafka/templates/configmap-jmx.yaml b/deployment/deployment/middleware_deployment/kafka/templates/configmap-jmx.yaml deleted file mode 100644 index 9eae921..0000000 --- a/deployment/deployment/middleware_deployment/kafka/templates/configmap-jmx.yaml +++ /dev/null @@ -1,64 +0,0 @@ -{{- if and .Values.prometheus.jmx.enabled .Values.jmx.configMap.enabled }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "kafka.fullname" . }}-metrics - labels: - {{- include "kafka.monitor.labels" . | nindent 4 }} -data: - jmx-kafka-prometheus.yml: |+ -{{- if .Values.jmx.configMap.overrideConfig }} -{{ toYaml .Values.jmx.configMap.overrideConfig | indent 4 }} -{{- else }} - jmxUrl: service:jmx:rmi:///jndi/rmi://127.0.0.1:{{ .Values.jmx.port }}/jmxrmi - lowercaseOutputName: true - lowercaseOutputLabelNames: true - ssl: false - {{ if .Values.jmx.whitelistObjectNames }} - whitelistObjectNames: ["{{ join "\",\"" .Values.jmx.whitelistObjectNames }}"] - {{ end }} - rules: - - pattern: kafka.controller<>(Value) - name: kafka_controller_$1_$2_$4 - labels: - broker_id: "$3" - - pattern: kafka.controller<>(Value) - name: kafka_controller_$1_$2_$3 - - pattern: kafka.controller<>(Value) - name: kafka_controller_$1_$2_$3 - - pattern: kafka.controller<>(Count) - name: kafka_controller_$1_$2_$3 - - pattern: kafka.server<>(Value) - name: kafka_server_$1_$2_$4 - labels: - client_id: "$3" - - pattern : kafka.network<>(Value) - name: kafka_network_$1_$2_$4 - labels: - network_processor: $3 - - pattern : kafka.network<>(Count) - name: kafka_network_$1_$2_$4 - labels: - request: $3 - - pattern: kafka.server<>(Count|OneMinuteRate) - name: kafka_server_$1_$2_$4 - labels: - topic: $3 - - pattern: kafka.server<>(Value) - name: kafka_server_$1_$2_$3_$4 - - pattern: kafka.server<>(Count|Value|OneMinuteRate) - name: kafka_server_$1_total_$2_$3 - - pattern: kafka.server<>(queue-size) - name: kafka_server_$1_$2 - - pattern: java.lang<(.+)>(\w+) - name: java_lang_$1_$4_$3_$2 - - pattern: java.lang<>(\w+) - name: java_lang_$1_$3_$2 - - pattern : java.lang - - pattern: kafka.log<>Value - name: kafka_log_$1_$2 - labels: - topic: $3 - partition: $4 -{{- end }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/kafka/templates/deployment-kafka-exporter.yaml b/deployment/deployment/middleware_deployment/kafka/templates/deployment-kafka-exporter.yaml deleted file mode 100644 index 85e5a60..0000000 --- a/deployment/deployment/middleware_deployment/kafka/templates/deployment-kafka-exporter.yaml +++ /dev/null @@ -1,45 +0,0 @@ -{{- if .Values.prometheus.kafka.enabled }} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ template "kafka.fullname" . }}-exporter - labels: - {{- include "kafka.monitor.labels" . | nindent 4 }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "kafka.monitor.matchLabels" . | nindent 6 }} - template: - metadata: - annotations: -{{- if and .Values.prometheus.kafka.enabled (not .Values.prometheus.operator.enabled) }} - prometheus.io/scrape: "true" - prometheus.io/port: {{ .Values.prometheus.kafka.port | quote }} -{{- end }} - labels: - {{- include "kafka.monitor.labels" . | nindent 8 }} - spec: - containers: - - image: "{{ .Values.prometheus.kafka.image }}:{{ .Values.prometheus.kafka.imageTag }}" - name: kafka-exporter - args: - - --kafka.server={{ template "kafka.fullname" . }}:9092 - - --web.listen-address=:{{ .Values.prometheus.kafka.port }} - ports: - - containerPort: {{ .Values.prometheus.kafka.port }} - resources: -{{ toYaml .Values.prometheus.kafka.resources | indent 10 }} -{{- if .Values.prometheus.kafka.tolerations }} - tolerations: -{{ toYaml .Values.prometheus.kafka.tolerations | indent 8 }} -{{- end }} -{{- if .Values.prometheus.kafka.affinity }} - affinity: -{{ toYaml .Values.prometheus.kafka.affinity | indent 8 }} -{{- end }} -{{- if .Values.prometheus.kafka.nodeSelector }} - nodeSelector: -{{ toYaml .Values.prometheus.kafka.nodeSelector | indent 8 }} -{{- end }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/kafka/templates/job-config.yaml b/deployment/deployment/middleware_deployment/kafka/templates/job-config.yaml deleted file mode 100644 index 13576b3..0000000 --- a/deployment/deployment/middleware_deployment/kafka/templates/job-config.yaml +++ /dev/null @@ -1,29 +0,0 @@ -{{- if .Values.topics -}} -{{- $scriptHash := include (print $.Template.BasePath "/configmap-config.yaml") . | sha256sum | trunc 8 -}} -apiVersion: batch/v1 -kind: Job -metadata: - name: "{{ template "kafka.fullname" . }}-config-{{ $scriptHash }}" - labels: - {{- include "kafka.config.labels" . | nindent 4 }} -spec: - backoffLimit: {{ .Values.configJob.backoffLimit }} - template: - metadata: - labels: - {{- include "kafka.config.matchLabels" . | nindent 8 }} - spec: - restartPolicy: OnFailure - volumes: - - name: config-volume - configMap: - name: {{ template "kafka.fullname" . }}-config - defaultMode: 0744 - containers: - - name: {{ template "kafka.fullname" . }}-config - image: "{{ .Values.image }}:{{ .Values.imageTag }}" - command: ["/usr/local/script/runtimeConfig.sh"] - volumeMounts: - - name: config-volume - mountPath: "/usr/local/script" -{{- end -}} diff --git a/deployment/deployment/middleware_deployment/kafka/templates/podisruptionbudget.yaml b/deployment/deployment/middleware_deployment/kafka/templates/podisruptionbudget.yaml deleted file mode 100644 index 7e1c03f..0000000 --- a/deployment/deployment/middleware_deployment/kafka/templates/podisruptionbudget.yaml +++ /dev/null @@ -1,14 +0,0 @@ -{{- if .Values.podDisruptionBudget }} -apiVersion: policy/v1beta1 -kind: PodDisruptionBudget -metadata: - name: {{ include "kafka.fullname" . }} - labels: - {{- include "kafka.broker.labels" . | nindent 4 }} -spec: - selector: - matchLabels: - {{- include "kafka.broker.matchLabels" . | nindent 6 }} -{{ toYaml .Values.podDisruptionBudget | indent 2 }} - -{{- end }} diff --git a/deployment/deployment/middleware_deployment/kafka/templates/prometheusrules.yaml b/deployment/deployment/middleware_deployment/kafka/templates/prometheusrules.yaml deleted file mode 100644 index 4f74ad5..0000000 --- a/deployment/deployment/middleware_deployment/kafka/templates/prometheusrules.yaml +++ /dev/null @@ -1,16 +0,0 @@ -{{ if and .Values.prometheus.operator.enabled .Values.prometheus.operator.prometheusRule.enabled .Values.prometheus.operator.prometheusRule.rules }} -apiVersion: monitoring.coreos.com/v1 -kind: PrometheusRule -metadata: - name: {{ include "kafka.fullname" . }} - namespace: {{ include "serviceMonitor.namespace" . }} - labels: - {{- include "kafka.monitor.labels" . | nindent 4 }} - {{- toYaml .Values.prometheus.operator.prometheusRule.selector | nindent 4 }} -spec: - groups: - - name: {{ include "kafka.fullname" . }} - rules: - {{- toYaml .Values.prometheus.operator.prometheusRule.rules | nindent 6 }} -{{- end }} - diff --git a/deployment/deployment/middleware_deployment/kafka/templates/service-brokers-external.yaml b/deployment/deployment/middleware_deployment/kafka/templates/service-brokers-external.yaml deleted file mode 100644 index e862728..0000000 --- a/deployment/deployment/middleware_deployment/kafka/templates/service-brokers-external.yaml +++ /dev/null @@ -1,77 +0,0 @@ -{{- if .Values.external.enabled }} - {{- $fullName := include "kafka.fullname" . }} - {{- $replicas := .Values.replicas | int }} - {{- $servicePort := .Values.external.servicePort }} - {{- $firstListenerPort := .Values.external.firstListenerPort }} - {{- $dnsPrefix := printf "%s" .Release.Name }} - {{- $root := . }} - {{- range $i, $e := until $replicas }} - {{- $externalListenerPort := add $root.Values.external.firstListenerPort $i }} - {{- $responsiblePod := printf "%s-%d" (printf "%s" $fullName) $i }} - {{- $distinctPrefix := printf "%s-%d" $dnsPrefix $i }} - {{- $loadBalancerIPLen := len $root.Values.external.loadBalancerIP }} - ---- -apiVersion: v1 -kind: Service -metadata: - annotations: - {{- if $root.Values.external.distinct }} - {{- if $root.Values.external.dns.useInternal }} - dns.alpha.kubernetes.io/internal: "{{ $distinctPrefix }}.{{ $root.Values.external.domain }}" - {{- end }} - {{- if $root.Values.external.dns.useExternal }} - external-dns.alpha.kubernetes.io/hostname: "{{ $distinctPrefix }}.{{ $root.Values.external.domain }}" - {{- end }} - {{- else }} - {{- if $root.Values.external.dns.useInternal }} - dns.alpha.kubernetes.io/internal: "{{ $dnsPrefix }}.{{ $root.Values.external.domain }}" - {{- end }} - {{- if $root.Values.external.dns.useExternal }} - external-dns.alpha.kubernetes.io/hostname: "{{ $dnsPrefix }}.{{ $root.Values.external.domain }}" - {{- end }} - {{- end }} - {{- if $root.Values.external.annotations }} -{{ toYaml $root.Values.external.annotations | indent 4 }} - {{- end }} - name: {{ $root.Release.Name }}-{{ $i }}-external - labels: - {{- include "kafka.broker.labels" $root | nindent 4 }} - pod: {{ $responsiblePod | quote }} - {{- if $root.Values.external.labels }} -{{ toYaml $root.Values.external.labels | indent 4 }} - {{- end }} -spec: - type: {{ $root.Values.external.type }} - ports: - - name: external-broker - {{- if and (eq $root.Values.external.type "LoadBalancer") (not $root.Values.external.distinct) }} - port: {{ $firstListenerPort }} - {{- else }} - port: {{ $servicePort }} - {{- end }} - {{- if and (eq $root.Values.external.type "LoadBalancer") ($root.Values.external.distinct) }} - targetPort: {{ $servicePort }} - {{- else if and (eq $root.Values.external.type "LoadBalancer") (not $root.Values.external.distinct) }} - targetPort: {{ $firstListenerPort }} - {{- else }} - targetPort: {{ $externalListenerPort }} - {{- end }} - {{- if eq $root.Values.external.type "NodePort" }} - nodePort: {{ $externalListenerPort }} - {{- end }} - protocol: TCP - {{- if and (eq $root.Values.external.type "LoadBalancer") (eq $loadBalancerIPLen $replicas) }} - loadBalancerIP: {{ index $root.Values.external.loadBalancerIP $i }} - {{- end }} - {{- if $root.Values.external.loadBalancerSourceRanges }} - loadBalancerSourceRanges: - {{- range $root.Values.external.loadBalancerSourceRanges }} - - {{ . | quote}} - {{- end }} - {{- end }} - selector: - {{- include "kafka.broker.matchLabels" $root | nindent 4 }} - statefulset.kubernetes.io/pod-name: {{ $responsiblePod | quote }} - {{- end }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/kafka/templates/service-brokers.yaml b/deployment/deployment/middleware_deployment/kafka/templates/service-brokers.yaml deleted file mode 100644 index 744843e..0000000 --- a/deployment/deployment/middleware_deployment/kafka/templates/service-brokers.yaml +++ /dev/null @@ -1,36 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ include "kafka.fullname" . }} - labels: - {{- include "kafka.broker.labels" . | nindent 4 }} -spec: - ports: - - name: broker - port: 9092 - targetPort: kafka -{{- if and .Values.prometheus.jmx.enabled .Values.prometheus.operator.enabled }} - - name: jmx-exporter - protocol: TCP - port: {{ .Values.jmx.port }} - targetPort: prometheus -{{- end }} - selector: - {{- include "kafka.broker.matchLabels" . | nindent 4 }} ---- -{{- if and .Values.prometheus.kafka.enabled .Values.prometheus.operator.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: {{ include "kafka.fullname" . }}-exporter - labels: - {{- include "kafka.monitor.labels" . | nindent 4 }} -spec: - ports: - - name: kafka-exporter - protocol: TCP - port: {{ .Values.prometheus.kafka.port }} - targetPort: {{ .Values.prometheus.kafka.port }} - selector: - {{- include "kafka.monitor.matchLabels" . | nindent 4 }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/kafka/templates/service-headless.yaml b/deployment/deployment/middleware_deployment/kafka/templates/service-headless.yaml deleted file mode 100644 index 2fa7cf7..0000000 --- a/deployment/deployment/middleware_deployment/kafka/templates/service-headless.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ include "kafka.fullname" . }}-headless - labels: - {{- include "kafka.broker.labels" . | nindent 4 }} - annotations: - service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" -{{- if .Values.headless.annotations }} -{{ .Values.headless.annotations | toYaml | trimSuffix "\n" | indent 4 }} -{{- end }} -spec: - ports: - - name: broker - port: {{ .Values.headless.port }} -{{- if .Values.headless.targetPort }} - targetPort: {{ .Values.headless.targetPort }} -{{- end }} - clusterIP: None - selector: - {{- include "kafka.broker.matchLabels" . | nindent 4 }} diff --git a/deployment/deployment/middleware_deployment/kafka/templates/servicemonitors.yaml b/deployment/deployment/middleware_deployment/kafka/templates/servicemonitors.yaml deleted file mode 100644 index 6d35feb..0000000 --- a/deployment/deployment/middleware_deployment/kafka/templates/servicemonitors.yaml +++ /dev/null @@ -1,47 +0,0 @@ -{{ if and .Values.prometheus.jmx.enabled .Values.prometheus.operator.enabled }} -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: {{ include "kafka.fullname" . }} - namespace: {{ include "serviceMonitor.namespace" . }} - labels: - {{- include "kafka.monitor.labels" . | nindent 4 }} - {{- toYaml .Values.prometheus.operator.serviceMonitor.selector | nindent 4 }} -spec: - selector: - matchLabels: - {{- include "kafka.broker.matchLabels" . | nindent 6 }} - endpoints: - - port: jmx-exporter - interval: {{ .Values.prometheus.jmx.interval }} - {{- if .Values.prometheus.jmx.scrapeTimeout }} - scrapeTimeout: {{ .Values.prometheus.jmx.scrapeTimeout }} - {{- end }} - namespaceSelector: - matchNames: - - {{ .Release.Namespace }} -{{ end }} ---- -{{ if and .Values.prometheus.kafka.enabled .Values.prometheus.operator.enabled }} -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: {{ include "kafka.fullname" . }}-exporter - namespace: {{ include "serviceMonitor.namespace" . }} - labels: - {{- include "kafka.monitor.labels" . | nindent 4 }} - {{ toYaml .Values.prometheus.operator.serviceMonitor.selector | nindent 4 }} -spec: - selector: - matchLabels: - {{- include "kafka.monitor.matchLabels" . | nindent 6 }} - endpoints: - - port: kafka-exporter - interval: {{ .Values.prometheus.kafka.interval }} - {{- if .Values.prometheus.kafka.scrapeTimeout }} - scrapeTimeout: {{ .Values.prometheus.kafka.scrapeTimeout }} - {{- end }} - namespaceSelector: - matchNames: - - {{ .Release.Namespace }} -{{ end }} diff --git a/deployment/deployment/middleware_deployment/kafka/templates/statefulset.yaml b/deployment/deployment/middleware_deployment/kafka/templates/statefulset.yaml deleted file mode 100644 index 5e056ec..0000000 --- a/deployment/deployment/middleware_deployment/kafka/templates/statefulset.yaml +++ /dev/null @@ -1,272 +0,0 @@ -{{- $advertisedListenersOverride := first (pluck "advertised.listeners" .Values.configurationOverrides) }} -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: {{ include "kafka.fullname" . }} - labels: - {{- include "kafka.broker.labels" . | nindent 4 }} -spec: - selector: - matchLabels: - {{- include "kafka.broker.matchLabels" . | nindent 6 }} - serviceName: {{ include "kafka.fullname" . }}-headless - podManagementPolicy: {{ .Values.podManagementPolicy }} - updateStrategy: -{{ toYaml .Values.updateStrategy | indent 4 }} - replicas: {{ default 3 .Values.replicas }} - template: - metadata: -{{- if or .Values.podAnnotations (and .Values.prometheus.jmx.enabled (not .Values.prometheus.operator.enabled)) }} - annotations: -{{- if and .Values.prometheus.jmx.enabled (not .Values.prometheus.operator.enabled) }} - prometheus.io/scrape: "true" - prometheus.io/port: {{ .Values.prometheus.jmx.port | quote }} -{{- end }} -{{- if .Values.podAnnotations }} -{{ toYaml .Values.podAnnotations | indent 8 }} -{{- end }} -{{- end }} - labels: - {{- include "kafka.broker.labels" . | nindent 8 }} - {{- if .Values.podLabels }} - ## Custom pod labels -{{ toYaml .Values.podLabels | indent 8 }} - {{- end }} - spec: -{{- if .Values.schedulerName }} - schedulerName: "{{ .Values.schedulerName }}" -{{- end }} -{{- if .Values.serviceAccountName }} - serviceAccountName: {{ .Values.serviceAccountName }} -{{- end }} -{{- if .Values.priorityClassName }} - priorityClassName: "{{ .Values.priorityClassName }}" -{{- end }} -{{- if .Values.tolerations }} - tolerations: -{{ toYaml .Values.tolerations | indent 8 }} -{{- end }} -{{- if .Values.affinity }} - affinity: -{{ toYaml .Values.affinity | indent 8 }} -{{- end }} -{{- if .Values.nodeSelector }} - nodeSelector: -{{ toYaml .Values.nodeSelector | indent 8 }} -{{- end }} - containers: - {{- if .Values.prometheus.jmx.enabled }} - - name: metrics - image: "{{ .Values.prometheus.jmx.image }}:{{ .Values.prometheus.jmx.imageTag }}" - command: - - sh - - -exc - - | - trap "exit 0" TERM; \ - while :; do \ - java \ - -XX:+UnlockExperimentalVMOptions \ - -XX:+UseCGroupMemoryLimitForHeap \ - -XX:MaxRAMFraction=1 \ - -XshowSettings:vm \ - -jar \ - jmx_prometheus_httpserver.jar \ - {{ .Values.prometheus.jmx.port | quote }} \ - /etc/jmx-kafka/jmx-kafka-prometheus.yml & \ - wait $! || sleep 3; \ - done - ports: - - containerPort: {{ .Values.prometheus.jmx.port }} - name: prometheus - resources: -{{ toYaml .Values.prometheus.jmx.resources | indent 10 }} - volumeMounts: - - name: jmx-config - mountPath: /etc/jmx-kafka - {{- end }} - - name: {{ include "kafka.name" . }}-broker - image: "{{ .Values.image }}:{{ .Values.imageTag }}" - imagePullPolicy: "{{ .Values.imagePullPolicy }}" - livenessProbe: - exec: - command: - - sh - - -ec - - /usr/bin/jps | /bin/grep -q SupportedKafka - {{- if not .Values.livenessProbe }} - initialDelaySeconds: 30 - timeoutSeconds: 5 - {{- else }} - initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds | default 30}} - {{- if .Values.livenessProbe.periodSeconds }} - periodSeconds: {{ .Values.livenessProbe.periodSeconds }} - {{- end }} - timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds | default 5}} - {{- if .Values.livenessProbe.successThreshold }} - successThreshold: {{ .Values.livenessProbe.successThreshold }} - {{- end }} - {{- if .Values.livenessProbe.failureThreshold }} - failureThreshold: {{ .Values.livenessProbe.failureThreshold }} - {{- end }} - {{- end }} - readinessProbe: - tcpSocket: - port: kafka - initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.readinessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} - successThreshold: {{ .Values.readinessProbe.successThreshold }} - failureThreshold: {{ .Values.readinessProbe.failureThreshold }} - ports: - - containerPort: 9092 - name: kafka - {{- if .Values.external.enabled }} - {{- $replicas := .Values.replicas | int }} - {{- $root := . }} - {{- range $i, $e := until $replicas }} - - containerPort: {{ add $root.Values.external.firstListenerPort $i }} - name: external-{{ $i }} - {{- end }} - {{- end }} - {{- if .Values.prometheus.jmx.enabled }} - - containerPort: {{ .Values.jmx.port }} - name: jmx - {{- end }} - {{- if .Values.additionalPorts }} -{{ toYaml .Values.additionalPorts | indent 8 }} - {{- end }} - resources: -{{ toYaml .Values.resources | indent 10 }} - env: - {{- if .Values.prometheus.jmx.enabled }} - - name: JMX_PORT - value: "{{ .Values.jmx.port }}" - {{- end }} - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: KAFKA_HEAP_OPTS - value: {{ .Values.kafkaHeapOptions }} - - name: KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR - value: {{ include "kafka.replication.factor" . | quote }} - {{- if not (hasKey .Values.configurationOverrides "zookeeper.connect") }} - - name: KAFKA_ZOOKEEPER_CONNECT - value: {{ include "zookeeper.url" . | quote }} - {{- end }} - {{- if not (hasKey .Values.configurationOverrides "log.dirs") }} - - name: KAFKA_LOG_DIRS - value: {{ printf "%s/%s" .Values.persistence.mountPath .Values.logSubPath | quote }} - {{- end }} - {{- range $key, $value := .Values.configurationOverrides }} - - name: {{ printf "KAFKA_%s" $key | replace "." "_" | upper | quote }} - value: {{ $value | quote }} - {{- end }} - {{- if .Values.jmx.port }} - - name: KAFKA_JMX_PORT - value: "{{ .Values.jmx.port }}" - {{- end }} - {{- range $secret := .Values.secrets }} - {{- if not $secret.mountPath }} - {{- range $key := $secret.keys }} - - name: {{ (print ($secret.name | replace "-" "_") "_" $key) | upper }} - valueFrom: - secretKeyRef: - name: {{ $secret.name }} - key: {{ $key }} - {{- end }} - {{- end }} - {{- end }} - {{- range $key, $value := .Values.envOverrides }} - - name: {{ printf "%s" $key | replace "." "_" | upper | quote }} - value: {{ $value | quote }} - {{- end }} - # This is required because the Downward API does not yet support identification of - # pod numbering in statefulsets. Thus, we are required to specify a command which - # allows us to extract the pod ID for usage as the Kafka Broker ID. - # See: https://github.com/kubernetes/kubernetes/issues/31218 - command: - - sh - - -exc - - | - unset KAFKA_PORT && \ - export KAFKA_BROKER_ID=${POD_NAME##*-} && \ - {{- if eq .Values.external.type "LoadBalancer" }} - export LOAD_BALANCER_IP=$(echo '{{ .Values.external.loadBalancerIP }}' | tr -d '[]' | cut -d ' ' -f "$(($KAFKA_BROKER_ID + 1))") && \ - {{- end }} - {{- if eq .Values.external.type "NodePort" }} - export KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://${POD_IP}:9092{{ if kindIs "string" $advertisedListenersOverride }}{{ printf ",%s" $advertisedListenersOverride }}{{ end }} && \ - {{- else }} - export KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://${POD_NAME}.{{ include "kafka.fullname" . }}-headless.${POD_NAMESPACE}.svc.cluster.local:9092{{ if kindIs "string" $advertisedListenersOverride }}{{ printf ",%s" $advertisedListenersOverride }}{{ end }} && \ - {{- end }} - exec /etc/confluent/docker/run - volumeMounts: - - name: datadir - mountPath: {{ .Values.persistence.mountPath | quote }} - {{- range $secret := .Values.secrets }} - {{- if $secret.mountPath }} - {{- if $secret.keys }} - {{- range $key := $secret.keys }} - - name: {{ include "kafka.fullname" $ }}-{{ $secret.name }} - mountPath: {{ $secret.mountPath }}/{{ $key }} - subPath: {{ $key }} - readOnly: true - {{- end }} - {{- else }} - - name: {{ include "kafka.fullname" $ }}-{{ $secret.name }} - mountPath: {{ $secret.mountPath }} - readOnly: true - {{- end }} - {{- end }} - {{- end }} - volumes: - {{- if not .Values.persistence.enabled }} - - name: datadir - emptyDir: {} - {{- end }} - {{- if .Values.prometheus.jmx.enabled }} - - name: jmx-config - configMap: - {{- if .Values.jmx.configMap.overrideName }} - name: {{ .Values.jmx.configMap.overrideName }} - {{- else }} - name: {{ include "kafka.fullname" . }}-metrics - {{- end }} - {{- end }} - {{- if .Values.securityContext }} - securityContext: -{{ toYaml .Values.securityContext | indent 8 }} - {{- end }} - {{- range .Values.secrets }} - {{- if .mountPath }} - - name: {{ include "kafka.fullname" $ }}-{{ .name }} - secret: - secretName: {{ .name }} - {{- end }} - {{- end }} - terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} - {{- if .Values.persistence.enabled }} - volumeClaimTemplates: - - metadata: - name: datadir - spec: - accessModes: [ "ReadWriteOnce" ] - resources: - requests: - storage: {{ .Values.persistence.size }} - {{- if .Values.persistence.storageClass }} - {{- if (eq "-" .Values.persistence.storageClass) }} - storageClassName: "" - {{- else }} - storageClassName: "{{ .Values.persistence.storageClass }}" - {{- end }} - {{- end }} - {{- end }} diff --git a/deployment/deployment/middleware_deployment/kafka/templates/tests/test_topic_create_consume_produce.yaml b/deployment/deployment/middleware_deployment/kafka/templates/tests/test_topic_create_consume_produce.yaml deleted file mode 100644 index e7dd5c9..0000000 --- a/deployment/deployment/middleware_deployment/kafka/templates/tests/test_topic_create_consume_produce.yaml +++ /dev/null @@ -1,25 +0,0 @@ -{{- if .Values.testsEnabled -}} -apiVersion: v1 -kind: Pod -metadata: - name: "{{ .Release.Name }}-test-topic-create-consume-produce" - annotations: - "helm.sh/hook": test-success -spec: - containers: - - name: {{ .Release.Name }}-test-consume - image: {{ .Values.image }}:{{ .Values.imageTag }} - command: - - sh - - -c - - | - # Create the topic - kafka-topics --zookeeper {{ include "zookeeper.url" . }} --topic helm-test-topic-create-consume-produce --create --partitions 1 --replication-factor 1 --if-not-exists && \ - # Create a message - MESSAGE="`date -u`" && \ - # Produce a test message to the topic - echo "$MESSAGE" | kafka-console-producer --broker-list {{ include "kafka.fullname" . }}:9092 --topic helm-test-topic-create-consume-produce && \ - # Consume a test message from the topic - kafka-console-consumer --bootstrap-server {{ include "kafka.fullname" . }}-headless:9092 --topic helm-test-topic-create-consume-produce --from-beginning --timeout-ms 2000 --max-messages 1 | grep "$MESSAGE" - restartPolicy: Never -{{- end }} \ No newline at end of file diff --git a/deployment/deployment/middleware_deployment/kafka/values.yaml b/deployment/deployment/middleware_deployment/kafka/values.yaml deleted file mode 100644 index 47e4235..0000000 --- a/deployment/deployment/middleware_deployment/kafka/values.yaml +++ /dev/null @@ -1,512 +0,0 @@ -# ------------------------------------------------------------------------------ -# Kafka: -# ------------------------------------------------------------------------------ - -## The StatefulSet installs 3 pods by default -replicas: 1 - -## The kafka image repository -image: "confluentinc/cp-kafka" - -## The kafka image tag -imageTag: "5.0.1" # Confluent image for Kafka 2.0.0 - -## Specify a imagePullPolicy -## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images -imagePullPolicy: "IfNotPresent" - -## Configure resource requests and limits -## ref: http://kubernetes.io/docs/user-guide/compute-resources/ -resources: {} - # limits: - # cpu: 200m - # memory: 1536Mi - # requests: - # cpu: 100m - # memory: 1024Mi -kafkaHeapOptions: "-Xmx1G -Xms1G" - -## Optional Container Security context -securityContext: {} - -## The StatefulSet Update Strategy which Kafka will use when changes are applied. -## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies -updateStrategy: - type: "OnDelete" - -## Start and stop pods in Parallel or OrderedReady (one-by-one.) Note - Can not change after first release. -## ref: https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/#pod-management-policy -podManagementPolicy: OrderedReady - -## Useful if using any custom authorizer -## Pass in some secrets to use (if required) -# secrets: -# - name: myKafkaSecret -# keys: -# - username -# - password -# # mountPath: /opt/kafka/secret -# - name: myZkSecret -# keys: -# - user -# - pass -# mountPath: /opt/zookeeper/secret - - -## The subpath within the Kafka container's PV where logs will be stored. -## This is combined with `persistence.mountPath`, to create, by default: /opt/kafka/data/logs -logSubPath: "logs" - -## Use an alternate scheduler, e.g. "stork". -## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ -## -# schedulerName: - -## Use an alternate serviceAccount -## Useful when using images in custom repositories -# serviceAccountName: - -## Set a pod priorityClassName -# priorityClassName: high-priority - -## Pod scheduling preferences (by default keep pods within a release on separate nodes). -## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity -## By default we don't set affinity -affinity: {} -## Alternatively, this typical example defines: -## antiAffinity (to keep Kafka pods on separate pods) -## and affinity (to encourage Kafka pods to be collocated with Zookeeper pods) -# affinity: -# podAntiAffinity: -# requiredDuringSchedulingIgnoredDuringExecution: -# - labelSelector: -# matchExpressions: -# - key: app -# operator: In -# values: -# - kafka -# topologyKey: "kubernetes.io/hostname" -# podAffinity: -# preferredDuringSchedulingIgnoredDuringExecution: -# - weight: 50 -# podAffinityTerm: -# labelSelector: -# matchExpressions: -# - key: app -# operator: In -# values: -# - zookeeper -# topologyKey: "kubernetes.io/hostname" - -## Node labels for pod assignment -## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector -nodeSelector: {} - -## Readiness probe config. -## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/ -## -readinessProbe: - initialDelaySeconds: 30 - periodSeconds: 10 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 3 - -## Period to wait for broker graceful shutdown (sigterm) before pod is killed (sigkill) -## ref: https://kubernetes-v1-4.github.io/docs/user-guide/production-pods/#lifecycle-hooks-and-termination-notice -## ref: https://kafka.apache.org/10/documentation.html#brokerconfigs controlled.shutdown.* -terminationGracePeriodSeconds: 60 - -# Tolerations for nodes that have taints on them. -# Useful if you want to dedicate nodes to just run kafka -# https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ -tolerations: [] -# tolerations: -# - key: "key" -# operator: "Equal" -# value: "value" -# effect: "NoSchedule" - -## Headless service. -## -headless: - # annotations: - # targetPort: - port: 9092 - -## External access. -## -external: - enabled: false - # type can be either NodePort or LoadBalancer - type: NodePort - # annotations: - # service.beta.kubernetes.io/openstack-internal-load-balancer: "true" - # Labels to be added to external services - # labels: - # aLabel: "value" - dns: - useInternal: false - useExternal: true - # If using external service type LoadBalancer and external dns, set distinct to true below. - # This creates an A record for each statefulset pod/broker. You should then map the - # A record of the broker to the EXTERNAL IP given by the LoadBalancer in your DNS server. - distinct: false - servicePort: 19092 - firstListenerPort: 31090 - domain: cluster.local - loadBalancerIP: [] - loadBalancerSourceRanges: [] - init: - image: "lwolf/kubectl_deployer" - imageTag: "0.4" - imagePullPolicy: "IfNotPresent" - -# Annotation to be added to Kafka pods -podAnnotations: {} - -# Labels to be added to Kafka pods -podLabels: {} - # service: broker - # team: developers - -podDisruptionBudget: {} - # maxUnavailable: 1 # Limits how many Kafka pods may be unavailable due to voluntary disruptions. - -## Configuration Overrides. Specify any Kafka settings you would like set on the StatefulSet -## here in map format, as defined in the official docs. -## ref: https://kafka.apache.org/documentation/#brokerconfigs -## -configurationOverrides: - "confluent.support.metrics.enable": false # Disables confluent metric submission - "zookeeper.connect": "zookeeper:2181" #Qke环境中否则为zookeeper.default.svc.cluster.local:2181 - # "auto.leader.rebalance.enable": true - "auto.create.topics.enable": true - # "controlled.shutdown.enable": true - # "controlled.shutdown.max.retries": 100 - - ## Options required for external access via NodePort - ## ref: - ## - http://kafka.apache.org/documentation/#security_configbroker - ## - https://cwiki.apache.org/confluence/display/KAFKA/KIP-103%3A+Separation+of+Internal+and+External+traffic - ## - ## Setting "advertised.listeners" here appends to "PLAINTEXT://${POD_IP}:9092,", ensure you update the domain - ## If external service type is Nodeport: - # "advertised.listeners": |- - # EXTERNAL://kafka.cluster.local:$((31090 + ${KAFKA_BROKER_ID})) - ## If external service type is LoadBalancer and distinct is true: - # "advertised.listeners": |- - # EXTERNAL://kafka-$((${KAFKA_BROKER_ID})).cluster.local:19092 - ## If external service type is LoadBalancer and distinct is false: - # "advertised.listeners": |- - # EXTERNAL://${LOAD_BALANCER_IP}:31090 - ## Uncomment to define the EXTERNAL Listener protocol - # "listener.security.protocol.map": |- - # PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT - -## set extra ENVs -# key: "value" -envOverrides: {} - - -## A collection of additional ports to expose on brokers (formatted as normal containerPort yaml) -# Useful when the image exposes metrics (like prometheus, etc.) through a javaagent instead of a sidecar -additionalPorts: {} - -## Persistence configuration. Specify if and how to persist data to a persistent volume. -## -persistence: - enabled: false - - ## The size of the PersistentVolume to allocate to each Kafka Pod in the StatefulSet. For - ## production servers this number should likely be much larger. - ## - size: "10Gi" - - ## The location within the Kafka container where the PV will mount its storage and Kafka will - ## store its logs. - ## - mountPath: "/opt/kafka/data" - - ## Kafka data 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: csi-high-perf - -jmx: - ## Rules to apply to the Prometheus JMX Exporter. Note while lots of stats have been cleaned and exposed, - ## there are still more stats to clean up and expose, others will never get exposed. They keep lots of duplicates - ## that can be derived easily. The configMap in this chart cleans up the metrics it exposes to be in a Prometheus - ## format, eg topic, broker are labels and not part of metric name. Improvements are gladly accepted and encouraged. - configMap: - - ## Allows disabling the default configmap, note a configMap is needed - enabled: true - - ## Allows setting values to generate confimap - ## To allow all metrics through (warning its crazy excessive) comment out below `overrideConfig` and set - ## `whitelistObjectNames: []` - overrideConfig: {} - # jmxUrl: service:jmx:rmi:///jndi/rmi://127.0.0.1:5555/jmxrmi - # lowercaseOutputName: true - # lowercaseOutputLabelNames: true - # ssl: false - # rules: - # - pattern: ".*" - - ## If you would like to supply your own ConfigMap for JMX metrics, supply the name of that - ## ConfigMap as an `overrideName` here. - overrideName: "" - - ## Port the jmx metrics are exposed in native jmx format, not in Prometheus format - port: 5555 - - ## JMX Whitelist Objects, can be set to control which JMX metrics are exposed. Only whitelisted - ## values will be exposed via JMX Exporter. They must also be exposed via Rules. To expose all metrics - ## (warning its crazy excessive and they aren't formatted in a prometheus style) (1) `whitelistObjectNames: []` - ## (2) commented out above `overrideConfig`. - whitelistObjectNames: # [] - - kafka.controller:* - - kafka.server:* - - java.lang:* - - kafka.network:* - - kafka.log:* - -## Prometheus Exporters / Metrics -## -prometheus: - ## Prometheus JMX Exporter: exposes the majority of Kafkas metrics - jmx: - enabled: false - - ## The image to use for the metrics collector - image: solsson/kafka-prometheus-jmx-exporter@sha256 - - ## The image tag to use for the metrics collector - imageTag: a23062396cd5af1acdf76512632c20ea6be76885dfc20cd9ff40fb23846557e8 - - ## Interval at which Prometheus scrapes metrics, note: only used by Prometheus Operator - interval: 10s - - ## Timeout at which Prometheus timeouts scrape run, note: only used by Prometheus Operator - scrapeTimeout: 10s - - ## Port jmx-exporter exposes Prometheus format metrics to scrape - port: 5556 - - resources: {} - # limits: - # cpu: 200m - # memory: 1Gi - # requests: - # cpu: 100m - # memory: 100Mi - - ## Prometheus Kafka Exporter: exposes complimentary metrics to JMX Exporter - kafka: - enabled: false - - ## The image to use for the metrics collector - image: danielqsj/kafka-exporter - - ## The image tag to use for the metrics collector - imageTag: v1.2.0 - - ## Interval at which Prometheus scrapes metrics, note: only used by Prometheus Operator - interval: 10s - - ## Timeout at which Prometheus timeouts scrape run, note: only used by Prometheus Operator - scrapeTimeout: 10s - - ## Port kafka-exporter exposes for Prometheus to scrape metrics - port: 9308 - - ## Resource limits - resources: {} -# limits: -# cpu: 200m -# memory: 1Gi -# requests: -# cpu: 100m -# memory: 100Mi - - # Tolerations for nodes that have taints on them. - # Useful if you want to dedicate nodes to just run kafka-exporter - # https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ - tolerations: [] - # tolerations: - # - key: "key" - # operator: "Equal" - # value: "value" - # effect: "NoSchedule" - - ## Pod scheduling preferences (by default keep pods within a release on separate nodes). - ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity - ## By default we don't set affinity - affinity: {} - ## Alternatively, this typical example defines: - ## affinity (to encourage Kafka Exporter pods to be collocated with Kafka pods) - # affinity: - # podAffinity: - # preferredDuringSchedulingIgnoredDuringExecution: - # - weight: 50 - # podAffinityTerm: - # labelSelector: - # matchExpressions: - # - key: app - # operator: In - # values: - # - kafka - # topologyKey: "kubernetes.io/hostname" - - ## Node labels for pod assignment - ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector - nodeSelector: {} - - operator: - ## Are you using Prometheus Operator? - enabled: false - - serviceMonitor: - # Namespace in which to install the ServiceMonitor resource. - namespace: monitoring - # Use release namespace instead - releaseNamespace: false - - ## Defaults to whats used if you follow CoreOS [Prometheus Install Instructions](https://github.com/coreos/prometheus-operator/tree/master/helm#tldr) - ## [Prometheus Selector Label](https://github.com/coreos/prometheus-operator/blob/master/helm/prometheus/templates/prometheus.yaml#L65) - ## [Kube Prometheus Selector Label](https://github.com/coreos/prometheus-operator/blob/master/helm/kube-prometheus/values.yaml#L298) - selector: - prometheus: kube-prometheus - - prometheusRule: - ## Add Prometheus Rules? - enabled: false - - ## Namespace in which to install the PrometheusRule resource. - namespace: monitoring - # Use release namespace instead - releaseNamespace: false - - ## Defaults to whats used if you follow CoreOS [Prometheus Install Instructions](https://github.com/coreos/prometheus-operator/tree/master/helm#tldr) - ## [Prometheus Selector Label](https://github.com/coreos/prometheus-operator/blob/master/helm/prometheus/templates/prometheus.yaml#L65) - ## [Kube Prometheus Selector Label](https://github.com/coreos/prometheus-operator/blob/master/helm/kube-prometheus/values.yaml#L298) - selector: - prometheus: kube-prometheus - - ## Some example rules. - ## e.g. max(kafka_controller_kafkacontroller_activecontrollercount_value{service="my-kafka-release"}) by (service) < 1 - rules: - - alert: KafkaNoActiveControllers - annotations: - message: The number of active controllers in {{ "{{" }} $labels.namespace {{ "}}" }} is less than 1. This usually means that some of the Kafka nodes aren't communicating properly. If it doesn't resolve itself you can try killing the pods (one by one whilst monitoring the under-replicated partitions graph). - expr: max(kafka_controller_kafkacontroller_activecontrollercount_value) by (namespace) < 1 - for: 5m - labels: - severity: critical - - alert: KafkaMultipleActiveControllers - annotations: - message: The number of active controllers in {{ "{{" }} $labels.namespace {{ "}}" }} is greater than 1. This usually means that some of the Kafka nodes aren't communicating properly. If it doesn't resolve itself you can try killing the pods (one by one whilst monitoring the under-replicated partitions graph). - expr: max(kafka_controller_kafkacontroller_activecontrollercount_value) by (namespace) > 1 - for: 5m - labels: - severity: critical - -## Kafka Config job configuration -## -configJob: - ## Specify the number of retries before considering kafka-config job as failed. - ## https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#pod-backoff-failure-policy - backoffLimit: 6 - -## Topic creation and configuration. -## The job will be run on a deployment only when the config has been changed. -## - If 'partitions' and 'replicationFactor' are specified we create the topic (with --if-not-exists.) -## - If 'partitions', 'replicationFactor' and 'reassignPartitions' are specified we reassign the partitions to -## increase the replication factor of an existing topic. -## - If 'partitions' is specified we 'alter' the number of partitions. This will -## silently and safely fail if the new setting isn’t strictly larger than the old (i.e. a NOOP.) Do be aware of the -## implications for keyed topics (ref: https://docs.confluent.io/current/kafka/post-deployment.html#admin-operations) -## - If 'defaultConfig' is specified it's deleted from the topic configuration. If it isn't present, -## it will silently and safely fail. -## - If 'config' is specified it's added to the topic configuration. -## -## Note: To increase the 'replicationFactor' of a topic, 'reassignPartitions' must be set to true (see above). -## -topics: [] - # - name: myExistingTopicConfig - # config: "cleanup.policy=compact,delete.retention.ms=604800000" - # - name: myExistingTopicReassignPartitions - # partitions: 8 - # replicationFactor: 5 - # reassignPartitions: true - # - name: myExistingTopicPartitions - # partitions: 8 - # - name: myNewTopicWithConfig - # partitions: 8 - # replicationFactor: 3 - # defaultConfig: "segment.bytes,segment.ms" - # config: "cleanup.policy=compact,delete.retention.ms=604800000" - # - name: myAclTopicPartitions - # partitions: 8 - # acls: - # - user: read - # operations: [ Read ] - # - user: read_and_write - # operations: - # - Read - # - Write - # - user: all - # operations: [ All ] - -## Enable/disable the chart's tests. Useful if using this chart as a dependency of -## another chart and you don't want these tests running when trying to develop and -## test your own chart. -testsEnabled: true - -# ------------------------------------------------------------------------------ -# Zookeeper: -# ------------------------------------------------------------------------------ - -zookeeper: - ## If true, install the Zookeeper chart alongside Kafka - ## ref: https://github.com/kubernetes/charts/tree/master/incubator/zookeeper - enabled: true - - ## Configure Zookeeper resource requests and limits - ## ref: http://kubernetes.io/docs/user-guide/compute-resources/ - resources: ~ - - ## Environmental variables to set in Zookeeper - env: - ## The JVM heap size to allocate to Zookeeper - ZK_HEAP_SIZE: "1G" - - persistence: - enabled: false - ## The amount of PV storage allocated to each Zookeeper pod in the statefulset - # size: "2Gi" - - ## Specify a Zookeeper imagePullPolicy - ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images - image: - PullPolicy: "IfNotPresent" - - ## If the Zookeeper Chart is disabled a URL and port are required to connect - url: "zookeeper.default.svc.cluster.local" - port: 2181 - - ## Pod scheduling preferences (by default keep pods within a release on separate nodes). - ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity - ## By default we don't set affinity: - affinity: {} # Criteria by which pod label-values influence scheduling for zookeeper pods. - # podAntiAffinity: - # requiredDuringSchedulingIgnoredDuringExecution: - # - topologyKey: "kubernetes.io/hostname" - # labelSelector: - # matchLabels: - # release: zookeeper diff --git a/deployment/deployment/middleware_deployment/mongodb/.helmignore b/deployment/deployment/middleware_deployment/mongodb/.helmignore deleted file mode 100644 index 6b8710a..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/.helmignore +++ /dev/null @@ -1 +0,0 @@ -.git diff --git a/deployment/deployment/middleware_deployment/mongodb/Chart.yaml b/deployment/deployment/middleware_deployment/mongodb/Chart.yaml deleted file mode 100644 index f86c4e3..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/Chart.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: v1 -name: mongodb -version: 7.8.10 -appVersion: 4.2.4 -# The mongodb chart is deprecated and no longer maintained. For details deprecation, see the PROCESSES.md file. -deprecated: true -description: DEPRECATED NoSQL document-oriented database that stores JSON-like documents with dynamic schemas, simplifying the integration of data in content-driven applications. -keywords: -- mongodb -- database -- nosql -- cluster -- replicaset -- replication -home: https://mongodb.org -icon: https://bitnami.com/assets/stacks/mongodb/img/mongodb-stack-220x234.png -sources: -- https://github.com/bitnami/bitnami-docker-mongodb -maintainers: [] -engine: gotpl diff --git a/deployment/deployment/middleware_deployment/mongodb/README.md b/deployment/deployment/middleware_deployment/mongodb/README.md deleted file mode 100644 index 0d592d5..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/README.md +++ /dev/null @@ -1,336 +0,0 @@ -# MongoDB - -[MongoDB](https://www.mongodb.com/) is a cross-platform document-oriented database. Classified as a NoSQL database, MongoDB eschews the traditional table-based relational database structure in favor of JSON-like documents with dynamic schemas, making the integration of data in certain types of applications easier and faster. - -## This Helm chart is deprecated - -Given the [`stable` deprecation timeline](https://github.com/helm/charts#deprecation-timeline), the Bitnami maintained MongoDB Helm chart is now located at [bitnami/charts](https://github.com/bitnami/charts/). - -The Bitnami repository is already included in the Hubs and we will continue providing the same cadence of updates, support, etc that we've been keeping here these years. Installation instructions are very similar, just adding the _bitnami_ repo and using it during the installation (`bitnami/` instead of `stable/`) - -```bash -$ helm repo add bitnami https://charts.bitnami.com/bitnami -$ helm install my-release bitnami/ # Helm 3 -$ helm install --name my-release bitnami/ # Helm 2 -``` - -To update an exisiting _stable_ deployment with a chart hosted in the bitnami repository you can execute - -```bash -$ helm repo add bitnami https://charts.bitnami.com/bitnami -$ helm upgrade my-release bitnami/ -``` - -Issues and PRs related to the chart itself will be redirected to `bitnami/charts` GitHub repository. In the same way, we'll be happy to answer questions related to this migration process in [this issue](https://github.com/helm/charts/issues/20969) created as a common place for discussion. - -## TL;DR; - -```bash -$ helm install my-release stable/mongodb -``` - -## Introduction - -This chart bootstraps a [MongoDB](https://github.com/bitnami/bitnami-docker-mongodb) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. - -Bitnami charts can be used with [Kubeapps](https://kubeapps.com/) for deployment and management of Helm Charts in clusters. This chart has been tested to work with NGINX Ingress, cert-manager, fluentd and Prometheus on top of the [BKPR](https://kubeprod.io/). - -## Prerequisites - -- Kubernetes 1.12+ -- Helm 2.11+ or Helm 3.0-beta3+ -- PV provisioner support in the underlying infrastructure -- ReadWriteMany volumes for deployment scaling - -## Installing the Chart - -To install the chart with the release name `my-release`: - -```bash -$ helm install my-release stable/mongodb -``` - -The command deploys MongoDB 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 - -The following table lists the configurable parameters of the MongoDB chart and their default values. - -| Parameter | Description | Default | -|----------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------| -| `global.imageRegistry` | Global Docker image registry | `nil` | -| `global.imagePullSecrets` | Global Docker registry secret names as an array | `[]` (does not add image pull secrets to deployed pods) | -| `global.storageClass` | Global storage class for dynamic provisioning | `nil` | -| `image.registry` | MongoDB image registry | `docker.io` | -| `image.repository` | MongoDB Image name | `bitnami/mongodb` | -| `image.tag` | MongoDB Image tag | `{TAG_NAME}` | -| `image.pullPolicy` | Image pull policy | `IfNotPresent` | -| `image.pullSecrets` | Specify docker-registry secret names as an array | `[]` (does not add image pull secrets to deployed pods) | -| `image.debug` | Specify if debug logs should be enabled | `false` | -| `nameOverride` | String to partially override mongodb.fullname template with a string (will prepend the release name) | `nil` | -| `fullnameOverride` | String to fully override mongodb.fullname template with a string | `nil` | -| `volumePermissions.enabled` | Enable init container that changes volume permissions in the data directory (for cases where the default k8s `runAsUser` and `fsUser` values do not work) | `false` | -| `volumePermissions.image.registry` | Init container volume-permissions image registry | `docker.io` | -| `volumePermissions.image.repository` | Init container volume-permissions image name | `bitnami/minideb` | -| `volumePermissions.image.tag` | Init container volume-permissions image tag | `buster` | -| `volumePermissions.image.pullPolicy` | Init container volume-permissions image pull policy | `Always` | -| `volumePermissions.resources` | Init container resource requests/limit | `nil` | -| `clusterDomain` | Default Kubernetes cluster domain | `cluster.local` | -| `usePassword` | Enable password authentication | `true` | -| `existingSecret` | Existing secret with MongoDB credentials | `nil` | -| `mongodbRootPassword` | MongoDB admin password | `random alphanumeric string (10)` | -| `mongodbUsername` | MongoDB custom user (mandatory if `mongodbDatabase` is set) | `nil` | -| `mongodbPassword` | MongoDB custom user password | `random alphanumeric string (10)` | -| `mongodbDatabase` | Database to create | `nil` | -| `mongodbEnableIPv6` | Switch to enable/disable IPv6 on MongoDB | `false` | -| `mongodbDirectoryPerDB` | Switch to enable/disable DirectoryPerDB on MongoDB | `false` | -| `mongodbSystemLogVerbosity` | MongoDB system log verbosity level | `0` | -| `mongodbDisableSystemLog` | Whether to disable MongoDB system log or not | `false` | -| `mongodbExtraFlags` | MongoDB additional command line flags | `[]` | -| `service.name` | Kubernetes service name | `nil` | -| `service.annotations` | Kubernetes service annotations, evaluated as a template | `{}` | -| `service.type` | Kubernetes Service type | `ClusterIP` | -| `service.clusterIP` | Static clusterIP or None for headless services | `nil` | -| `service.port` | MongoDB service port | `27017` | -| `service.nodePort` | Port to bind to for NodePort service type | `nil` | -| `service.loadBalancerIP` | Static IP Address to use for LoadBalancer service type | `nil` | -| `service.externalIPs` | External IP list to use with ClusterIP service type | `[]` | -| `service.loadBalancerSourceRanges` | List of IP ranges allowed access to load balancer (if supported) | `[]` (does not add IP range restrictions to the service) | -| `replicaSet.enabled` | Switch to enable/disable replica set configuration | `false` | -| `replicaSet.name` | Name of the replica set | `rs0` | -| `replicaSet.useHostnames` | Enable DNS hostnames in the replica set config | `true` | -| `replicaSet.key` | Key used for authentication in the replica set | `random alphanumeric string (10)` | -| `replicaSet.replicas.secondary` | Number of secondary nodes in the replica set | `1` | -| `replicaSet.replicas.arbiter` | Number of arbiter nodes in the replica set | `1` | -| `replicaSet.pdb.enabled` | Switch to enable/disable Pod Disruption Budget | `true` | -| `replicaSet.pdb.minAvailable.secondary` | PDB (min available) for the MongoDB Secondary nodes | `1` | -| `replicaSet.pdb.minAvailable.arbiter` | PDB (min available) for the MongoDB Arbiter nodes | `1` | -| `replicaSet.pdb.maxUnavailable.secondary` | PDB (max unavailable) for the MongoDB Secondary nodes | `nil` | -| `replicaSet.pdb.maxUnavailable.arbiter` | PDB (max unavailable) for the MongoDB Arbiter nodes | `nil` | -| `annotations` | Annotations to be added to the deployment or statefulsets | `{}` | -| `labels` | Additional labels for the deployment or statefulsets | `{}` | -| `podAnnotations` | Annotations to be added to pods | `{}` | -| `podLabels` | Additional labels for the pod(s). | `{}` | -| `resources` | Pod resources | `{}` | -| `resourcesArbiter` | Pod resources for arbiter when replica set is enabled | `{}` | -| `priorityClassName` | Pod priority class name | `` | -| `extraEnvVars` | Array containing extra env vars to be added to all pods in the cluster (evaluated as a template) | `nil` | -| `nodeSelector` | Node labels for pod assignment | `{}` | -| `affinity` | Affinity for pod assignment | `{}` | -| `affinityArbiter` | Affinity for arbiter pod assignment | `{}` | -| `tolerations` | Toleration labels for pod assignment | `{}` | -| `updateStrategy` | Statefulsets update strategy policy | `RollingUpdate` | -| `securityContext.enabled` | Enable security context | `true` | -| `securityContext.fsGroup` | Group ID for the container | `1001` | -| `securityContext.runAsUser` | User ID for the container | `1001` | -| `schedulerName` | Name of the k8s scheduler (other than default) | `nil` | -| `sidecars` | Add additional containers to pod | `[]` | -| `extraVolumes` | Add additional volumes to deployment | `[]` | -| `extraVolumeMounts` | Add additional volumes mounts to pod | `[]` | -| `sidecarsArbiter` | Add additional containers to arbiter pod | `[]` | -| `extraVolumesArbiter` | Add additional volumes to arbiter deployment | `[]` | -| `extraVolumeMountsArbiter` | Add additional volumes mounts to arbiter pod | `[]` | -| `persistence.enabled` | Use a PVC to persist data | `true` | -| `persistence.mountPath` | Path to mount the volume at | `/bitnami/mongodb` | -| `persistence.subPath` | Subdirectory of the volume to mount at | `""` | -| `persistence.storageClass` | Storage class of backing PVC | `nil` (uses alpha storage class annotation) | -| `persistence.accessModes` | Use volume as ReadOnly or ReadWrite | `[ReadWriteOnce]` | -| `persistence.size` | Size of data volume | `8Gi` | -| `persistence.annotations` | Persistent Volume annotations | `{}` | -| `persistence.existingClaim` | Name of an existing PVC to use (avoids creating one if this is given) | `nil` | -| `useStatefulSet` | Set to true to use StatefulSet instead of Deployment even when replicaSet.enalbed=false | `nil` | -| `extraInitContainers` | Additional init containers as a string to be passed to the `tpl` function | `{}` | -| `livenessProbe.enabled` | Enable/disable the Liveness probe | `true` | -| `livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | `30` | -| `livenessProbe.periodSeconds` | How often to perform the probe | `10` | -| `livenessProbe.timeoutSeconds` | When the probe times out | `5` | -| `livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed. | `1` | -| `livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | `6` | -| `readinessProbe.enabled` | Enable/disable the Readiness probe | `true` | -| `readinessProbe.initialDelaySeconds` | Delay before readiness probe is initiated | `5` | -| `readinessProbe.periodSeconds` | How often to perform the probe | `10` | -| `readinessProbe.timeoutSeconds` | When the probe times out | `5` | -| `readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | `6` | -| `readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed. | `1` | -| `initConfigMap.name` | Custom config map with init scripts | `nil` | -| `configmap` | MongoDB configuration file to be used | `nil` | -| `ingress.enabled` | Enable ingress controller resource | `false` | -| `ingress.certManager` | Add annotations for cert-manager | `false` | -| `ingress.annotations` | Ingress annotations | `[]` | -| `ingress.hosts[0].name` | Hostname to your MongoDB installation | `mongodb.local` | -| `ingress.hosts[0].path` | Path within the url structure | `/` | -| `ingress.tls[0].hosts[0]` | TLS hosts | `mongodb.local` | -| `ingress.tls[0].secretName` | TLS Secret (certificates) | `mongodb.local-tls` | -| `ingress.secrets[0].name` | TLS Secret Name | `nil` | -| `ingress.secrets[0].certificate` | TLS Secret Certificate | `nil` | -| `ingress.secrets[0].key` | TLS Secret Key | `nil` | -| `metrics.enabled` | Start a side-car prometheus exporter | `false` | -| `metrics.image.registry` | MongoDB exporter image registry | `docker.io` | -| `metrics.image.repository` | MongoDB exporter image name | `bitnami/mongodb-exporter` | -| `metrics.image.tag` | MongoDB exporter image tag | `{TAG_NAME}` | -| `metrics.image.pullPolicy` | Image pull policy | `Always` | -| `metrics.image.pullSecrets` | Specify docker-registry secret names as an array | `[]` (does not add image pull secrets to deployed pods) | -| `metrics.podAnnotations.prometheus.io/scrape` | Additional annotations for Metrics exporter pod | `true` | -| `metrics.podAnnotations.prometheus.io/port` | Additional annotations for Metrics exporter pod | `"9216"` | -| `metrics.extraArgs` | String with extra arguments for the MongoDB Exporter | `` | -| `metrics.resources` | Exporter resource requests/limit | `{}` | -| `metrics.serviceMonitor.enabled` | Create ServiceMonitor Resource for scraping metrics using PrometheusOperator | `false` | -| `metrics.serviceMonitor.namespace` | Optional namespace which Prometheus is running in | `nil` | -| `metrics.serviceMonitor.additionalLabels` | Used to pass Labels that are required by the Installed Prometheus Operator | `{}` | -| `metrics.serviceMonitor.relabellings` | Specify Metric Relabellings to add to the scrape endpoint | `nil` | -| `metrics.serviceMonitor.alerting.rules` | Define individual alerting rules as required | `{}` | -| `metrics.serviceMonitor.alerting.additionalLabels` | Used to pass Labels that are required by the Installed Prometheus Operator | `{}` | -| `metrics.livenessProbe.enabled` | Enable/disable the Liveness Check of Prometheus metrics exporter | `false` | -| `metrics.livenessProbe.initialDelaySeconds` | Initial Delay for Liveness Check of Prometheus metrics exporter | `15` | -| `metrics.livenessProbe.periodSeconds` | How often to perform Liveness Check of Prometheus metrics exporter | `5` | -| `metrics.livenessProbe.timeoutSeconds` | Timeout for Liveness Check of Prometheus metrics exporter | `5` | -| `metrics.livenessProbe.failureThreshold` | Failure Threshold for Liveness Check of Prometheus metrics exporter | `3` | -| `metrics.livenessProbe.successThreshold` | Success Threshold for Liveness Check of Prometheus metrics exporter | `1` | -| `metrics.readinessProbe.enabled` | Enable/disable the Readiness Check of Prometheus metrics exporter | `false` | -| `metrics.readinessProbe.initialDelaySeconds` | Initial Delay for Readiness Check of Prometheus metrics exporter | `5` | -| `metrics.readinessProbe.periodSeconds` | How often to perform Readiness Check of Prometheus metrics exporter | `5` | -| `metrics.readinessProbe.timeoutSeconds` | Timeout for Readiness Check of Prometheus metrics exporter | `1` | -| `metrics.readinessProbe.failureThreshold` | Failure Threshold for Readiness Check of Prometheus metrics exporter | `3` | -| `metrics.readinessProbe.successThreshold` | Success Threshold for Readiness Check of Prometheus metrics exporter | `1` | - - -Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, - -```bash -$ helm install my-release \ - --set mongodbRootPassword=secretpassword,mongodbUsername=my-user,mongodbPassword=my-password,mongodbDatabase=my-database \ - stable/mongodb -``` - -The above command sets the MongoDB `root` account password to `secretpassword`. Additionally, it creates a standard database user named `my-user`, with the password `my-password`, who has access to a database named `my-database`. - -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 stable/mongodb -``` - -> **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. - -### Production configuration and horizontal scaling - -This chart includes a `values-production.yaml` file where you can find some parameters oriented to production configuration in comparison to the regular `values.yaml`. You can use this file instead of the default one. - -- Switch to enable/disable replica set configuration: -```diff -- replicaSet.enabled: false -+ replicaSet.enabled: true -``` - -- Start a side-car prometheus exporter: -```diff -- metrics.enabled: false -+ metrics.enabled: true -``` - -- Enable/disable the Liveness Check of Prometheus metrics exporter: -```diff -- metrics.livenessProbe.enabled: false -+ metrics.livenessProbe.enabled: true -``` - -- Enable/disable the Readiness Check of Prometheus metrics exporter: -```diff -- metrics.readinessProbe.enabled: false -+ metrics.readinessProbe.enabled: true -``` - -To horizontally scale this chart, you can use the `--replicas` flag to modify the number of secondary nodes in your MongoDB replica set. - -### Replication - -You can start the MongoDB chart in replica set mode with the following parameter: `replicaSet.enabled=true` - -Some characteristics of this chart are: - -- Each of the participants in the replication has a fixed stateful set so you always know where to find the primary, secondary or arbiter nodes. -- The number of secondary and arbiter nodes can be scaled out independently. -- Easy to move an application from using a standalone MongoDB server to use a replica set. - -### Initialize a fresh instance - -The [Bitnami MongoDB](https://github.com/bitnami/bitnami-docker-mongodb) image allows you to use your custom scripts to initialize a fresh instance. In order to execute the scripts, they must be located inside the chart folder `files/docker-entrypoint-initdb.d` so they can be consumed as a ConfigMap. -Also you can create a custom config map and give it via `initConfigMap`(check options for more details). - -The allowed extensions are `.sh`, and `.js`. - -## Persistence - -The [Bitnami MongoDB](https://github.com/bitnami/bitnami-docker-mongodb) image stores the MongoDB data and configurations at the `/bitnami/mongodb` path of the container. - -The chart mounts a [Persistent Volume](http://kubernetes.io/docs/user-guide/persistent-volumes/) at this location. The volume is created using dynamic volume provisioning. - -### 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`. - -## Upgrading - -### To 7.0.0 -From this version, the way of setting the ingress rules has changed. Instead of using `ingress.paths` and `ingress.hosts` as separate objects, you should now define the rules as objects inside the `ingress.hosts` value, for example: - -```yaml -ingress: - hosts: - - name: mongodb.local - path: / -``` - -### To 6.0.0 - -From this version, `mongodbEnableIPv6` is set to `false` by default in order to work properly in most k8s clusters, if you want to use IPv6 support, you need to set this variable to `true` by adding `--set mongodbEnableIPv6=true` to your `helm` command. -You can find more information in the [`bitnami/mongodb` image README](https://github.com/bitnami/bitnami-docker-mongodb/blob/master/README.md). - -### To 5.0.0 - -When enabling replicaset configuration, backwards compatibility is not guaranteed unless you modify the labels used on the chart's statefulsets. -Use the workaround below to upgrade from versions previous to 5.0.0. The following example assumes that the release name is `my-release`: - -```console -$ kubectl delete statefulset my-release-mongodb-arbiter my-release-mongodb-primary my-release-mongodb-secondary --cascade=false -``` - -## Configure Ingress -MongoDB can exposed externally using an Ingress controller. To do so, it's necessary to: - -- Install the MongoDB chart setting the parameter `ingress.enabled=true`. -- Create a ConfigMap to map the external port to use and the internal service/port where to redirect the requests (see https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/exposing-tcp-udp-services.md for more information). - -For instance, if you installed the MongoDB chart in the `default` namespace, you can install the [stable/nginx-ingress chart](https://github.com/helm/charts/tree/master/stable/nginx-ingress) setting the "tcp" parameter in the **values.yaml** used to install the chart as shown below: - -```yaml -... - -tcp: - 27017: "default/mongodb:27017" -``` diff --git a/deployment/deployment/middleware_deployment/mongodb/files/docker-entrypoint-initdb.d/README.md b/deployment/deployment/middleware_deployment/mongodb/files/docker-entrypoint-initdb.d/README.md deleted file mode 100644 index a929990..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/files/docker-entrypoint-initdb.d/README.md +++ /dev/null @@ -1,3 +0,0 @@ -You can copy here your custom .sh, or .js file so they are executed during the first boot of the image. - -More info in the [bitnami-docker-mongodb](https://github.com/bitnami/bitnami-docker-mongodb#initializing-a-new-instance) repository. \ No newline at end of file diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/NOTES.txt b/deployment/deployment/middleware_deployment/mongodb/templates/NOTES.txt deleted file mode 100644 index 7145f73..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/NOTES.txt +++ /dev/null @@ -1,96 +0,0 @@ -This Helm chart is deprecated - -Given the `stable` deprecation timeline (https://github.com/helm/charts#deprecation-timeline), the Bitnami maintained Helm chart is now located at bitnami/charts (https://github.com/bitnami/charts/). - -The Bitnami repository is already included in the Hubs and we will continue providing the same cadence of updates, support, etc that we've been keeping here these years. Installation instructions are very similar, just adding the _bitnami_ repo and using it during the installation (`bitnami/` instead of `stable/`) - -```bash -$ helm repo add bitnami https://charts.bitnami.com/bitnami -$ helm install my-release bitnami/ # Helm 3 -$ helm install --name my-release bitnami/ # Helm 2 -``` - -To update an exisiting _stable_ deployment with a chart hosted in the bitnami repository you can execute - -```bash -$ helm repo add bitnami https://charts.bitnami.com/bitnami -$ helm upgrade my-release bitnami/ -``` - -Issues and PRs related to the chart itself will be redirected to `bitnami/charts` GitHub repository. In the same way, we'll be happy to answer questions related to this migration process in this issue (https://github.com/helm/charts/issues/20969) created as a common place for discussion. - -{{- if contains .Values.service.type "LoadBalancer" }} -{{- if not .Values.mongodbRootPassword }} -------------------------------------------------------------------------------- - WARNING - - By specifying "service.type=LoadBalancer" and not specifying "mongodbRootPassword" - you have most likely exposed the MongoDB service externally without any - authentication mechanism. - - For security reasons, we strongly suggest that you switch to "ClusterIP" or - "NodePort". As alternative, you can also specify a valid password on the - "mongodbRootPassword" parameter. - -------------------------------------------------------------------------------- -{{- end }} -{{- end }} - -** Please be patient while the chart is being deployed ** - -MongoDB can be accessed via port {{ .Values.service.port }} on the following DNS name from within your cluster: - - {{ template "mongodb.serviceName" . }}.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }} - -{{ if .Values.usePassword -}} - -To get the root password run: - - export MONGODB_ROOT_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "mongodb.fullname" . }} -o jsonpath="{.data.mongodb-root-password}" | base64 --decode) - -{{- end }} -{{- if and .Values.mongodbUsername .Values.mongodbDatabase }} -{{- if .Values.mongodbPassword }} - -To get the password for "{{ .Values.mongodbUsername }}" run: - - export MONGODB_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "mongodb.fullname" . }} -o jsonpath="{.data.mongodb-password}" | base64 --decode) - -{{- end }} -{{- end }} - -To connect to your database run the following command: - - kubectl run --namespace {{ .Release.Namespace }} {{ template "mongodb.fullname" . }}-client --rm --tty -i --restart='Never' --image {{ template "mongodb.image" . }} --command -- mongo admin --host {{ template "mongodb.serviceName" . }} {{- if .Values.usePassword }} --authenticationDatabase admin -u root -p $MONGODB_ROOT_PASSWORD{{- end }} - -To connect to your database from outside the cluster execute the following commands: - -{{- if contains "NodePort" .Values.service.type }} - - export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "mongodb.serviceName" . }}) - mongo --host $NODE_IP --port $NODE_PORT {{- if .Values.usePassword }} --authenticationDatabase admin -p $MONGODB_ROOT_PASSWORD{{- end }} - -{{- else if contains "LoadBalancer" .Values.service.type }} - - NOTE: It may take a few minutes for the LoadBalancer IP to be available. - Watch the status with: 'kubectl get svc --namespace {{ .Release.Namespace }} -w {{ template "mongodb.serviceName" . }}' - - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "mongodb.serviceName" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - mongo --host $SERVICE_IP --port {{ .Values.service.port }} {{- if .Values.usePassword }} --authenticationDatabase admin -p $MONGODB_ROOT_PASSWORD{{- end }} - -{{- else if contains "ClusterIP" .Values.service.type }} - - kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ template "mongodb.serviceName" . }} {{ .Values.service.port }}:{{ .Values.service.port }} & - mongo --host 127.0.0.1 {{- if .Values.usePassword }} --authenticationDatabase admin -p $MONGODB_ROOT_PASSWORD{{- end }} - -{{- end }} - -{{- include "mongodb.validateValues" . -}} - -{{- if and (contains "bitnami/" .Values.image.repository) (not (.Values.image.tag | toString | regexFind "-r\\d+$|sha256:")) }} - -WARNING: Rolling tag detected ({{ .Values.image.repository }}:{{ .Values.image.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 }} diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/_helpers.tpl b/deployment/deployment/middleware_deployment/mongodb/templates/_helpers.tpl deleted file mode 100644 index 47f1bb2..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/_helpers.tpl +++ /dev/null @@ -1,252 +0,0 @@ -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "mongodb.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Renders a value that contains template. -Usage: -{{ include "mongodb.tplValue" ( dict "value" .Values.path.to.the.Value "context" $) }} -*/}} -{{- define "mongodb.tplValue" -}} - {{- if typeIs "string" .value }} - {{- tpl .value .context }} - {{- else }} - {{- tpl (.value | toYaml) .context }} - {{- end }} -{{- 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 "mongodb.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "mongodb.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create the name for the admin secret. -*/}} -{{- define "mongodb.adminSecret" -}} - {{- if .Values.auth.existingAdminSecret -}} - {{- .Values.auth.existingAdminSecret -}} - {{- else -}} - {{- template "mongodb.fullname" . -}}-admin - {{- end -}} -{{- end -}} - -{{/* -Create the name for the key secret. -*/}} -{{- define "mongodb.keySecret" -}} - {{- if .Values.auth.existingKeySecret -}} - {{- .Values.auth.existingKeySecret -}} - {{- else -}} - {{- template "mongodb.fullname" . -}}-keyfile - {{- end -}} -{{- end -}} - -{{/* -Return the proper MongoDB image name -*/}} -{{- define "mongodb.image" -}} -{{- $registryName := .Values.image.registry -}} -{{- $repositoryName := .Values.image.repository -}} -{{- $tag := .Values.image.tag | toString -}} -{{/* -Helm 2.11 supports the assignment of a value to a variable defined in a different scope, -but Helm 2.9 and 2.10 doesn't support it, so we need to implement this if-else logic. -Also, we can't use a single if because lazy evaluation is not an option -*/}} -{{- if .Values.global }} - {{- if .Values.global.imageRegistry }} - {{- printf "%s/%s:%s" .Values.global.imageRegistry $repositoryName $tag -}} - {{- else -}} - {{- printf "%s/%s:%s" $registryName $repositoryName $tag -}} - {{- end -}} -{{- else -}} - {{- printf "%s/%s:%s" $registryName $repositoryName $tag -}} -{{- end -}} -{{- end -}} - -{{/* -Return the proper image name (for the metrics image) -*/}} -{{- define "mongodb.metrics.image" -}} -{{- $registryName := .Values.metrics.image.registry -}} -{{- $repositoryName := .Values.metrics.image.repository -}} -{{- $tag := .Values.metrics.image.tag | toString -}} -{{/* -Helm 2.11 supports the assignment of a value to a variable defined in a different scope, -but Helm 2.9 and 2.10 doesn't support it, so we need to implement this if-else logic. -Also, we can't use a single if because lazy evaluation is not an option -*/}} -{{- if .Values.global }} - {{- if .Values.global.imageRegistry }} - {{- printf "%s/%s:%s" .Values.global.imageRegistry $repositoryName $tag -}} - {{- else -}} - {{- printf "%s/%s:%s" $registryName $repositoryName $tag -}} - {{- end -}} -{{- else -}} - {{- printf "%s/%s:%s" $registryName $repositoryName $tag -}} -{{- end -}} -{{- end -}} - - -{{/* -Return the proper Docker Image Registry Secret Names -*/}} -{{- define "mongodb.imagePullSecrets" -}} -{{/* -Helm 2.11 supports the assignment of a value to a variable defined in a different scope, -but Helm 2.9 and 2.10 does not support it, so we need to implement this if-else logic. -Also, we can not use a single if because lazy evaluation is not an option -*/}} -{{- if .Values.global }} -{{- if .Values.global.imagePullSecrets }} -imagePullSecrets: -{{- range .Values.global.imagePullSecrets }} - - name: {{ . }} -{{- end }} -{{- else if or .Values.image.pullSecrets .Values.metrics.image.pullSecrets .Values.volumePermissions.image.pullSecrets }} -imagePullSecrets: -{{- range .Values.image.pullSecrets }} - - name: {{ . }} -{{- end }} -{{- range .Values.metrics.image.pullSecrets }} - - name: {{ . }} -{{- end }} -{{- range .Values.volumePermissions.image.pullSecrets }} - - name: {{ . }} -{{- end }} -{{- end -}} -{{- else if or .Values.image.pullSecrets .Values.metrics.image.pullSecrets .Values.volumePermissions.image.pullSecrets }} -imagePullSecrets: -{{- range .Values.image.pullSecrets }} - - name: {{ . }} -{{- end }} -{{- range .Values.metrics.image.pullSecrets }} - - name: {{ . }} -{{- end }} -{{- range .Values.volumePermissions.image.pullSecrets }} - - name: {{ . }} -{{- end }} -{{- end -}} -{{- end -}} - -{{/* -Return the proper image name (for the init container volume-permissions image) -*/}} -{{- define "mongodb.volumePermissions.image" -}} -{{- $registryName := .Values.volumePermissions.image.registry -}} -{{- $repositoryName := .Values.volumePermissions.image.repository -}} -{{- $tag := .Values.volumePermissions.image.tag | toString -}} -{{/* -Helm 2.11 supports the assignment of a value to a variable defined in a different scope, -but Helm 2.9 and 2.10 doesn't support it, so we need to implement this if-else logic. -Also, we can't use a single if because lazy evaluation is not an option -*/}} -{{- if .Values.global }} - {{- if .Values.global.imageRegistry }} - {{- printf "%s/%s:%s" .Values.global.imageRegistry $repositoryName $tag -}} - {{- else -}} - {{- printf "%s/%s:%s" $registryName $repositoryName $tag -}} - {{- end -}} -{{- else -}} - {{- printf "%s/%s:%s" $registryName $repositoryName $tag -}} -{{- end -}} -{{- end -}} - -{{/* -Compile all warnings into a single message, and call fail. -*/}} -{{- define "mongodb.validateValues" -}} -{{- $messages := list -}} -{{- $messages := append $messages (include "mongodb.validateValues.mongodbCustomDatabase" .) -}} -{{- $messages := without $messages "" -}} -{{- $message := join "\n" $messages -}} - -{{- if $message -}} -{{- printf "\nVALUES VALIDATION:\n%s" $message | fail -}} -{{- end -}} -{{- end -}} - -{{/* -Validate values of MongoDB - both mongodbUsername and mongodbDatabase are necessary -to create a custom user and database during 1st initialization -*/}} -{{- define "mongodb.validateValues.mongodbCustomDatabase" -}} -{{- if or (and .Values.mongodbUsername (not .Values.mongodbDatabase)) (and (not .Values.mongodbUsername) .Values.mongodbDatabase) }} -mongodb: mongodbUsername, mongodbDatabase - Both mongodbUsername and mongodbDatabase must be provided to create - a custom user and database during 1st initialization. - Please set both of them (--set mongodbUsername="xxxx",mongodbDatabase="yyyy") -{{- end -}} -{{- end -}} - -{{/* -Return the proper Storage Class -*/}} -{{- define "mongodb.storageClass" -}} -{{/* -Helm 2.11 supports the assignment of a value to a variable defined in a different scope, -but Helm 2.9 and 2.10 does not support it, so we need to implement this if-else logic. -*/}} -{{- if .Values.global -}} - {{- if .Values.global.storageClass -}} - {{- if (eq "-" .Values.global.storageClass) -}} - {{- printf "storageClassName: \"\"" -}} - {{- else }} - {{- printf "storageClassName: %s" .Values.global.storageClass -}} - {{- end -}} - {{- else -}} - {{- if .Values.persistence.storageClass -}} - {{- if (eq "-" .Values.persistence.storageClass) -}} - {{- printf "storageClassName: \"\"" -}} - {{- else }} - {{- printf "storageClassName: %s" .Values.persistence.storageClass -}} - {{- end -}} - {{- end -}} - {{- end -}} -{{- else -}} - {{- if .Values.persistence.storageClass -}} - {{- if (eq "-" .Values.persistence.storageClass) -}} - {{- printf "storageClassName: \"\"" -}} - {{- else }} - {{- printf "storageClassName: %s" .Values.persistence.storageClass -}} - {{- end -}} - {{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Returns the proper Service name depending if an explicit service name is set -in the values file. If the name is not explicitly set it will take the "mongodb.fullname" -*/}} -{{- define "mongodb.serviceName" -}} - {{- if .Values.service.name -}} - {{ .Values.service.name }} - {{- else -}} - {{ template "mongodb.fullname" .}} - {{- end -}} -{{- end -}} diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/configmap.yaml b/deployment/deployment/middleware_deployment/mongodb/templates/configmap.yaml deleted file mode 100644 index 66dc853..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/configmap.yaml +++ /dev/null @@ -1,14 +0,0 @@ -{{- if .Values.configmap }} -apiVersion: v1 -kind: ConfigMap -metadata: - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - name: {{ template "mongodb.fullname" . }} -data: - mongodb.conf: |- -{{ toYaml .Values.configmap | indent 4 }} -{{- end }} \ No newline at end of file diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/deployment-standalone.yaml b/deployment/deployment/middleware_deployment/mongodb/templates/deployment-standalone.yaml deleted file mode 100644 index 4951598..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/deployment-standalone.yaml +++ /dev/null @@ -1,304 +0,0 @@ -{{- if not .Values.replicaSet.enabled }} -apiVersion: apps/v1 -kind: {{ if .Values.useStatefulSet }}{{ "StatefulSet" }}{{- else }}{{ "Deployment" }}{{- end }} -metadata: - name: {{ template "mongodb.fullname" . }} - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" - {{- with .Values.labels }} -{{ toYaml . | indent 4 }} - {{- end }} - {{- with .Values.annotations }} - annotations: -{{ toYaml . | indent 4 }} - {{- end }} -spec: - {{- if .Values.useStatefulSet }} - serviceName: {{ template "mongodb.serviceName" . }} - updateStrategy: - {{- else }} - strategy: - {{- end }} - type: {{ .Values.updateStrategy.type }} - {{- if (eq "Recreate" .Values.updateStrategy.type) }} - rollingUpdate: null - {{- end }} - selector: - matchLabels: - app: {{ template "mongodb.name" . }} - release: "{{ .Release.Name }}" - template: - metadata: - labels: - app: {{ template "mongodb.name" . }} - release: "{{ .Release.Name }}" - chart: {{ template "mongodb.chart" . }} - {{- if .Values.podLabels }} -{{ toYaml .Values.podLabels | indent 8 }} - {{- end }} - {{- if or .Values.podAnnotations .Values.metrics.enabled }} - annotations: -{{- if .Values.podAnnotations }} -{{ toYaml .Values.podAnnotations | indent 8 }} -{{- end }} -{{- if .Values.metrics.enabled }} -{{ toYaml .Values.metrics.podAnnotations | indent 8 }} -{{- end }} - {{- end }} - spec: - {{- if .Values.schedulerName }} - schedulerName: "{{ .Values.schedulerName }}" - {{- end }} - {{- if .Values.priorityClassName }} - priorityClassName: {{ .Values.priorityClassName }} - {{- end }} - {{- if .Values.securityContext.enabled }} - securityContext: - fsGroup: {{ .Values.securityContext.fsGroup }} - {{- end }} - {{- if .Values.affinity }} - affinity: -{{ toYaml .Values.affinity | indent 8 }} - {{- end -}} - {{- if .Values.nodeSelector }} - nodeSelector: -{{ toYaml .Values.nodeSelector | indent 8 }} - {{- end }} - {{- if .Values.tolerations }} - tolerations: -{{ toYaml .Values.tolerations | indent 8 }} - {{- end }} -{{- include "mongodb.imagePullSecrets" . | indent 6 }} - initContainers: - {{- if .Values.extraInitContainers }} -{{ tpl .Values.extraInitContainers . | indent 6}} - {{- end }} - {{- if and .Values.volumePermissions.enabled .Values.persistence.enabled }} - - name: volume-permissions - image: {{ template "mongodb.volumePermissions.image" . }} - imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} - command: ["chown", "-R", "{{ .Values.securityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }}", "{{ .Values.persistence.mountPath }}"] - securityContext: - runAsUser: 0 - resources: {{ toYaml .Values.volumePermissions.resources | nindent 10 }} - volumeMounts: - - name: data - mountPath: {{ .Values.persistence.mountPath }} - {{- end }} - containers: - - name: {{ template "mongodb.fullname" . }} - image: {{ template "mongodb.image" . }} - imagePullPolicy: {{ .Values.image.pullPolicy | quote }} - {{- if .Values.securityContext.enabled }} - securityContext: - runAsNonRoot: true - runAsUser: {{ .Values.securityContext.runAsUser }} - {{- end }} - env: - {{- if .Values.image.debug}} - - name: BITNAMI_DEBUG - value: "true" - {{- end }} - {{- if .Values.usePassword }} - {{- if and .Values.mongodbUsername .Values.mongodbDatabase }} - - name: MONGODB_PASSWORD - valueFrom: - secretKeyRef: - name: {{ if .Values.existingSecret }}{{ .Values.existingSecret }}{{- else }}{{ template "mongodb.fullname" . }}{{- end }} - key: mongodb-password - {{- end }} - - name: MONGODB_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: {{ if .Values.existingSecret }}{{ .Values.existingSecret }}{{- else }}{{ template "mongodb.fullname" . }}{{- end }} - key: mongodb-root-password - {{- end }} - {{- if .Values.mongodbUsername }} - - name: MONGODB_USERNAME - value: {{ .Values.mongodbUsername | quote }} - {{- end }} - - name: MONGODB_SYSTEM_LOG_VERBOSITY - value: {{ .Values.mongodbSystemLogVerbosity | quote }} - - name: MONGODB_DISABLE_SYSTEM_LOG - {{- if .Values.mongodbDisableSystemLog }} - value: "yes" - {{- else }} - value: "no" - {{- end }} - {{- if .Values.mongodbDatabase }} - - name: MONGODB_DATABASE - value: {{ .Values.mongodbDatabase | quote }} - {{- end }} - - name: MONGODB_ENABLE_IPV6 - {{- if .Values.mongodbEnableIPv6 }} - value: "yes" - {{- else }} - value: "no" - {{- end }} - - name: MONGODB_ENABLE_DIRECTORY_PER_DB - {{- if .Values.mongodbDirectoryPerDB }} - value: "yes" - {{- else }} - value: "no" - {{- end }} - {{- if .Values.mongodbExtraFlags }} - - name: MONGODB_EXTRA_FLAGS - value: {{ .Values.mongodbExtraFlags | join " " | quote }} - {{- end }} - {{- if .Values.extraEnvVars }} - {{- include "mongodb.tplValue" ( dict "value" .Values.extraEnvVars "context" $ ) | nindent 8 }} - {{- end }} - ports: - - name: mongodb - containerPort: 27017 - {{- if .Values.livenessProbe.enabled }} - livenessProbe: - exec: - command: - - mongo - - --eval - - "db.adminCommand('ping')" - initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.livenessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} - successThreshold: {{ .Values.livenessProbe.successThreshold }} - failureThreshold: {{ .Values.livenessProbe.failureThreshold }} - {{- end }} - {{- if .Values.readinessProbe.enabled }} - readinessProbe: - exec: - command: - - mongo - - --eval - - "db.adminCommand('ping')" - initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.readinessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} - successThreshold: {{ .Values.readinessProbe.successThreshold }} - failureThreshold: {{ .Values.readinessProbe.failureThreshold }} - {{- end }} - volumeMounts: - - name: data - mountPath: {{ .Values.persistence.mountPath }} - subPath: {{ .Values.persistence.subPath }} - {{- if or (.Files.Glob "files/docker-entrypoint-initdb.d/*[sh|js|json]") (.Values.initConfigMap) }} - - name: custom-init-scripts - mountPath: /docker-entrypoint-initdb.d - {{- end }} - {{- if .Values.configmap }} - - name: config - mountPath: /opt/bitnami/mongodb/conf/mongodb.conf - subPath: mongodb.conf - {{- end }} - {{- if .Values.extraVolumeMounts }} -{{ toYaml .Values.extraVolumeMounts | indent 8}} - {{- end }} - resources: -{{ toYaml .Values.resources | indent 10 }} -{{- if .Values.metrics.enabled }} - - name: metrics - image: {{ template "mongodb.metrics.image" . }} - imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} - {{- if .Values.securityContext.enabled }} - securityContext: - runAsNonRoot: true - runAsUser: {{ .Values.securityContext.runAsUser }} - {{- end }} - env: - {{- if .Values.usePassword }} - - name: MONGODB_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: {{ if .Values.existingSecret }}{{ .Values.existingSecret }}{{- else }}{{ template "mongodb.fullname" . }}{{- end }} - key: mongodb-root-password - command: [ 'sh', '-c', '/bin/mongodb_exporter --mongodb.uri mongodb://root:${MONGODB_ROOT_PASSWORD}@localhost:{{ .Values.service.port }}/admin {{ .Values.metrics.extraArgs }}' ] - {{- else }} - command: [ 'sh', '-c', '/bin/mongodb_exporter --mongodb.uri mongodb://localhost:{{ .Values.service.port }} {{ .Values.metrics.extraArgs }}' ] - {{- end }} - ports: - - name: metrics - containerPort: 9216 - {{- if .Values.metrics.livenessProbe.enabled }} - livenessProbe: - httpGet: - path: /metrics - port: metrics - initialDelaySeconds: {{ .Values.metrics.livenessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.metrics.readinessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.metrics.livenessProbe.timeoutSeconds }} - failureThreshold: {{ .Values.metrics.livenessProbe.failureThreshold }} - successThreshold: {{ .Values.metrics.livenessProbe.successThreshold }} - {{- end }} - {{- if .Values.metrics.readinessProbe.enabled }} - readinessProbe: - httpGet: - path: /metrics - port: metrics - initialDelaySeconds: {{ .Values.metrics.readinessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.metrics.readinessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.metrics.readinessProbe.timeoutSeconds }} - failureThreshold: {{ .Values.metrics.readinessProbe.failureThreshold }} - successThreshold: {{ .Values.metrics.readinessProbe.successThreshold }} - {{- end }} - resources: -{{ toYaml .Values.metrics.resources | indent 10 }} -{{- end }} -{{- if .Values.sidecars }} -{{ toYaml .Values.sidecars | indent 6 }} -{{- end }} - volumes: - {{- if (.Files.Glob "files/docker-entrypoint-initdb.d/*[sh|js|json]") }} - - name: custom-init-scripts - configMap: - name: {{ template "mongodb.fullname" . }}-init-scripts - {{- end }} - {{- if (.Values.initConfigMap) }} - - name: custom-init-scripts - configMap: - name: {{ .Values.initConfigMap.name }} - {{- end }} - - name: data - {{- if not .Values.useStatefulSet }} - {{- if .Values.persistence.enabled }} - persistentVolumeClaim: - claimName: {{ if .Values.persistence.existingClaim }}{{ .Values.persistence.existingClaim }}{{- else }}{{ template "mongodb.fullname" . }}{{- end }} - - {{- else }} - emptyDir: {} - {{- end -}} - {{- end -}} - {{- if .Values.configmap }} - - name: config - configMap: - name: {{ template "mongodb.fullname" . }} - {{- end }} - {{- if .Values.extraVolumes }} -{{ toYaml .Values.extraVolumes | indent 6}} - {{- end }} -{{- if .Values.useStatefulSet }} -{{- if .Values.persistence.enabled }} - volumeClaimTemplates: - - metadata: - name: data - annotations: - {{- range $key, $value := .Values.persistence.annotations }} - {{ $key }}: "{{ $value }}" - {{- end }} - spec: - accessModes: - {{- range .Values.persistence.accessModes }} - - {{ . | quote }} - {{- end }} - resources: - requests: - storage: {{ .Values.persistence.size | quote }} - {{ include "mongodb.storageClass" . }} -{{- else }} - - name: data - emptyDir: {} -{{- end }} -{{- end }} -{{- end -}} diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/ingress.yaml b/deployment/deployment/middleware_deployment/mongodb/templates/ingress.yaml deleted file mode 100644 index 669c33b..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/ingress.yaml +++ /dev/null @@ -1,33 +0,0 @@ -{{- if .Values.ingress.enabled }} -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: {{ template "mongodb.fullname" . }} - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" - annotations: - {{- if .Values.ingress.certManager }} - kubernetes.io/tls-acme: "true" - {{- end }} - {{- range $key, $value := .Values.ingress.annotations }} - {{ $key }}: {{ $value | quote }} - {{- end }} -spec: - rules: - {{- range .Values.ingress.hosts }} - - host: {{ .name }} - http: - paths: - - path: {{ default "/" .path }} - backend: - serviceName: {{ template "mongodb.serviceName" $ }} - servicePort: mongodb - {{- end }} - {{- if .Values.ingress.tls }} - tls: -{{ toYaml .Values.ingress.tls | indent 4 }} - {{- end }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/initialization-configmap.yaml b/deployment/deployment/middleware_deployment/mongodb/templates/initialization-configmap.yaml deleted file mode 100644 index 02da7df..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/initialization-configmap.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{ if (.Files.Glob "files/docker-entrypoint-initdb.d/*[sh|js|json]") }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "mongodb.fullname" . }}-init-scripts - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - release: {{ .Release.Name | quote }} - heritage: {{ .Release.Service | quote }} -data: -{{ tpl (.Files.Glob "files/docker-entrypoint-initdb.d/*[sh|js|json]").AsConfig . | indent 2 }} -{{ end }} diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/poddisruptionbudget-arbiter-rs.yaml b/deployment/deployment/middleware_deployment/mongodb/templates/poddisruptionbudget-arbiter-rs.yaml deleted file mode 100644 index b97fb72..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/poddisruptionbudget-arbiter-rs.yaml +++ /dev/null @@ -1,27 +0,0 @@ -{{- if and .Values.replicaSet.enabled .Values.replicaSet.pdb.enabled }} -apiVersion: policy/v1beta1 -kind: PodDisruptionBudget -metadata: - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - name: {{ template "mongodb.fullname" . }}-arbiter -spec: - {{- if .Values.replicaSet.pdb.minAvailable }} - {{- if .Values.replicaSet.pdb.minAvailable.arbiter }} - minAvailable: {{ .Values.replicaSet.pdb.minAvailable.arbiter }} - {{- end }} - {{- end }} - {{- if .Values.replicaSet.pdb.maxUnavailable }} - {{- if .Values.replicaSet.pdb.maxUnavailable.arbiter }} - maxUnavailable: {{ .Values.replicaSet.pdb.maxUnavailable.arbiter }} - {{- end }} - {{- end }} - selector: - matchLabels: - app: {{ template "mongodb.name" . }} - release: {{ .Release.Name }} - component: arbiter -{{- end }} \ No newline at end of file diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/poddisruptionbudget-secondary-rs.yaml b/deployment/deployment/middleware_deployment/mongodb/templates/poddisruptionbudget-secondary-rs.yaml deleted file mode 100644 index 1fc2cdf..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/poddisruptionbudget-secondary-rs.yaml +++ /dev/null @@ -1,27 +0,0 @@ -{{- if and .Values.replicaSet.enabled .Values.replicaSet.pdb.enabled }} -apiVersion: policy/v1beta1 -kind: PodDisruptionBudget -metadata: - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - name: {{ template "mongodb.fullname" . }}-secondary -spec: - {{- if .Values.replicaSet.pdb.minAvailable }} - {{- if .Values.replicaSet.pdb.minAvailable.secondary }} - minAvailable: {{ .Values.replicaSet.pdb.minAvailable.secondary }} - {{- end }} - {{- end }} - {{- if .Values.replicaSet.pdb.maxUnavailable }} - {{- if .Values.replicaSet.pdb.maxUnavailable.secondary }} - maxUnavailable: {{ .Values.replicaSet.pdb.maxUnavailable.secondary }} - {{- end }} - {{- end }} - selector: - matchLabels: - app: {{ template "mongodb.name" . }} - release: {{ .Release.Name }} - component: secondary -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/prometheus-alerting-rule.yaml b/deployment/deployment/middleware_deployment/mongodb/templates/prometheus-alerting-rule.yaml deleted file mode 100644 index e6d4d4c..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/prometheus-alerting-rule.yaml +++ /dev/null @@ -1,17 +0,0 @@ -{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled .Values.metrics.serviceMonitor.alerting.rules }} -apiVersion: monitoring.coreos.com/v1 -kind: PrometheusRule -metadata: - name: {{ template "mongodb.fullname" . }} - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - {{- if .Values.metrics.serviceMonitor.alerting.additionalLabels }} -{{ toYaml .Values.metrics.serviceMonitor.alerting.additionalLabels | indent 4 }} - {{- end }} -spec: - groups: -{{ toYaml .Values.metrics.serviceMonitor.alerting.rules | indent 4 }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/prometheus-service-monitor.yaml b/deployment/deployment/middleware_deployment/mongodb/templates/prometheus-service-monitor.yaml deleted file mode 100644 index 8900b34..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/prometheus-service-monitor.yaml +++ /dev/null @@ -1,35 +0,0 @@ -{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: {{ template "mongodb.fullname" . }} - {{- if .Values.metrics.serviceMonitor.namespace }} - namespace: {{ .Values.metrics.serviceMonitor.namespace }} - {{- end }} - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - {{- if .Values.metrics.serviceMonitor.additionalLabels }} -{{ toYaml .Values.metrics.serviceMonitor.additionalLabels | indent 4 }} - {{- end }} -spec: - endpoints: - - interval: 30s - port: metrics - {{- if .Values.metrics.serviceMonitor.relabellings }} - metricRelabelings: -{{ toYaml .Values.metrics.serviceMonitor.relabellings | indent 4 }} - {{- end }} - jobLabel: {{ template "mongodb.fullname" . }} - namespaceSelector: - matchNames: - - "{{ $.Release.Namespace }}" - selector: - matchLabels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/pvc-standalone.yaml b/deployment/deployment/middleware_deployment/mongodb/templates/pvc-standalone.yaml deleted file mode 100644 index f4e114d..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/pvc-standalone.yaml +++ /dev/null @@ -1,20 +0,0 @@ -{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) (not .Values.replicaSet.enabled) (not .Values.useStatefulSet) }} -kind: PersistentVolumeClaim -apiVersion: v1 -metadata: - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - name: {{ template "mongodb.fullname" . }} -spec: - accessModes: - {{- range .Values.persistence.accessModes }} - - {{ . | quote }} - {{- end }} - resources: - requests: - storage: {{ .Values.persistence.size | quote }} - {{ include "mongodb.storageClass" . }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/secrets.yaml b/deployment/deployment/middleware_deployment/mongodb/templates/secrets.yaml deleted file mode 100644 index bf644cb..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/secrets.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{ if and .Values.usePassword (not .Values.existingSecret) -}} -apiVersion: v1 -kind: Secret -metadata: - name: {{ template "mongodb.fullname" . }} - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" -type: Opaque -data: - {{- if .Values.mongodbRootPassword }} - mongodb-root-password: {{ .Values.mongodbRootPassword | b64enc | quote }} - {{- else }} - mongodb-root-password: {{ randAlphaNum 10 | b64enc | quote }} - {{- end }} - {{- if and .Values.mongodbUsername .Values.mongodbDatabase }} - {{- if .Values.mongodbPassword }} - mongodb-password: {{ .Values.mongodbPassword | b64enc | quote }} - {{- else }} - mongodb-password: {{ randAlphaNum 10 | b64enc | quote }} - {{- end }} - {{- end }} - {{- if .Values.replicaSet.enabled }} - {{- if .Values.replicaSet.key }} - mongodb-replica-set-key: {{ .Values.replicaSet.key | b64enc | quote }} - {{- else }} - mongodb-replica-set-key: {{ randAlphaNum 10 | b64enc | quote }} - {{- end }} - {{- end }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/statefulset-arbiter-rs.yaml b/deployment/deployment/middleware_deployment/mongodb/templates/statefulset-arbiter-rs.yaml deleted file mode 100644 index 9b7169e..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/statefulset-arbiter-rs.yaml +++ /dev/null @@ -1,187 +0,0 @@ -{{- if .Values.replicaSet.enabled }} -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: {{ template "mongodb.fullname" . }}-arbiter - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - {{- with .Values.labels }} -{{ toYaml . | indent 4 }} - {{- end }} - {{- with .Values.annotations }} - annotations: -{{ toYaml . | indent 4 }} - {{- end }} -spec: - selector: - matchLabels: - app: {{ template "mongodb.name" . }} - release: {{ .Release.Name }} - component: arbiter - serviceName: {{ template "mongodb.fullname" . }}-headless - replicas: {{ .Values.replicaSet.replicas.arbiter }} - updateStrategy: - type: {{ .Values.updateStrategy.type }} - {{- if (eq "Recreate" .Values.updateStrategy.type) }} - rollingUpdate: null - {{- end }} - template: - metadata: - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - release: {{ .Release.Name }} - component: arbiter - {{- if .Values.podLabels }} -{{ toYaml .Values.podLabels | indent 8 }} - {{- end }} - {{- if .Values.podAnnotations }} - annotations: -{{ toYaml .Values.podAnnotations | indent 8 }} - {{- end }} - spec: - {{- if .Values.schedulerName }} - schedulerName: "{{ .Values.schedulerName }}" - {{- end }} - {{- if .Values.priorityClassName }} - priorityClassName: {{ .Values.priorityClassName }} - {{- end }} - {{- if .Values.securityContext.enabled }} - securityContext: - fsGroup: {{ .Values.securityContext.fsGroup }} - {{- end }} - {{- if .Values.affinityArbiter }} - affinity: -{{ toYaml .Values.affinityArbiter | indent 8 }} - {{- end -}} - {{- if .Values.nodeSelector }} - nodeSelector: -{{ toYaml .Values.nodeSelector | indent 8 }} - {{- end }} - {{- if .Values.tolerations }} - tolerations: -{{ toYaml .Values.tolerations | indent 8 }} - {{- end }} -{{- include "mongodb.imagePullSecrets" . | indent 6 }} - {{- if .Values.extraInitContainers }} - initContainers: -{{ tpl .Values.extraInitContainers . | indent 6}} - {{- end }} - containers: - - name: {{ template "mongodb.name" . }}-arbiter - image: {{ template "mongodb.image" . }} - imagePullPolicy: {{ .Values.image.pullPolicy }} - {{- if .Values.securityContext.enabled }} - securityContext: - runAsNonRoot: true - runAsUser: {{ .Values.securityContext.runAsUser }} - {{- end }} - ports: - - containerPort: {{ .Values.service.port }} - name: mongodb - env: - {{- if .Values.image.debug}} - - name: BITNAMI_DEBUG - value: "true" - {{- end }} - - name: MONGODB_SYSTEM_LOG_VERBOSITY - value: {{ .Values.mongodbSystemLogVerbosity | quote }} - - name: MONGODB_DISABLE_SYSTEM_LOG - {{- if .Values.mongodbDisableSystemLog }} - value: "yes" - {{- else }} - value: "no" - {{- end }} - - name: MONGODB_POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: MONGODB_REPLICA_SET_MODE - value: "arbiter" - - name: MONGODB_PRIMARY_HOST - value: {{ template "mongodb.fullname" . }} - - name: MONGODB_REPLICA_SET_NAME - value: {{ .Values.replicaSet.name | quote }} - {{- if .Values.replicaSet.useHostnames }} - - name: MONGODB_ADVERTISED_HOSTNAME - value: "$(MONGODB_POD_NAME).{{ template "mongodb.fullname" . }}-headless.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }}" - {{- end }} - {{- if .Values.usePassword }} - - name: MONGODB_PRIMARY_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: {{ if .Values.existingSecret }}{{ .Values.existingSecret }}{{- else }}{{ template "mongodb.fullname" . }}{{- end }} - key: mongodb-root-password - - name: MONGODB_REPLICA_SET_KEY - valueFrom: - secretKeyRef: - name: {{ if .Values.existingSecret }}{{ .Values.existingSecret }}{{- else }}{{ template "mongodb.fullname" . }}{{- end }} - key: mongodb-replica-set-key - {{- end }} - - name: MONGODB_ENABLE_IPV6 - {{- if .Values.mongodbEnableIPv6 }} - value: "yes" - {{- else }} - value: "no" - {{- end }} - - name: MONGODB_ENABLE_DIRECTORY_PER_DB - {{- if .Values.mongodbDirectoryPerDB }} - value: "yes" - {{- else }} - value: "no" - {{- end }} - {{- if .Values.mongodbExtraFlags }} - - name: MONGODB_EXTRA_FLAGS - value: {{ .Values.mongodbExtraFlags | join " " | quote }} - {{- end }} - {{- if .Values.extraEnvVars }} - {{- include "mongodb.tplValue" ( dict "value" .Values.extraEnvVars "context" $ ) | nindent 10 }} - {{- end }} - {{- if .Values.livenessProbe.enabled }} - livenessProbe: - tcpSocket: - port: mongodb - initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.livenessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} - successThreshold: {{ .Values.livenessProbe.successThreshold }} - failureThreshold: {{ .Values.livenessProbe.failureThreshold }} - {{- end }} - {{- if .Values.readinessProbe.enabled }} - readinessProbe: - tcpSocket: - port: mongodb - initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.readinessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} - successThreshold: {{ .Values.readinessProbe.successThreshold }} - failureThreshold: {{ .Values.readinessProbe.failureThreshold }} - {{- end }} - volumeMounts: - {{- if .Values.configmap }} - - name: config - mountPath: /opt/bitnami/mongodb/conf/mongodb.conf - subPath: mongodb.conf - {{- end }} - resources: -{{ toYaml .Values.resourcesArbiter | indent 12 }} -{{- if .Values.extraVolumeMountsArbiter }} - volumeMounts: -{{ toYaml .Values.extraVolumeMountsArbiter | indent 12}} -{{- end }} -{{- if .Values.sidecarsArbiter }} -{{ toYaml .Values.sidecarsArbiter | indent 8 }} -{{- end }} - volumes: - {{- if .Values.configmap }} - - name: config - configMap: - name: {{ template "mongodb.fullname" . }} - {{- end }} - {{- if .Values.extraVolumesArbiter }} -{{ toYaml .Values.extraVolumesArbiter | indent 8 }} - {{- end }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/statefulset-primary-rs.yaml b/deployment/deployment/middleware_deployment/mongodb/templates/statefulset-primary-rs.yaml deleted file mode 100644 index a6f585c..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/statefulset-primary-rs.yaml +++ /dev/null @@ -1,307 +0,0 @@ -{{- if .Values.replicaSet.enabled }} -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: {{ template "mongodb.fullname" . }}-primary - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - {{- with .Values.labels }} -{{ toYaml . | indent 4 }} - {{- end }} - {{- with .Values.annotations }} - annotations: -{{ toYaml . | indent 4 }} - {{- end }} -spec: - serviceName: {{ template "mongodb.fullname" . }}-headless - replicas: 1 - updateStrategy: - type: {{ .Values.updateStrategy.type }} - {{- if (eq "Recreate" .Values.updateStrategy.type) }} - rollingUpdate: null - {{- end }} - selector: - matchLabels: - app: {{ template "mongodb.name" . }} - release: {{ .Release.Name }} - component: primary - template: - metadata: - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - release: {{ .Release.Name }} - component: primary - {{- if .Values.podLabels }} -{{ toYaml .Values.podLabels | indent 8 }} - {{- end }} - {{- if or .Values.podAnnotations .Values.metrics.enabled }} - annotations: -{{- if .Values.podAnnotations }} -{{ toYaml .Values.podAnnotations | indent 8 }} -{{- end }} -{{- if .Values.metrics.enabled }} -{{ toYaml .Values.metrics.podAnnotations | indent 8 }} -{{- end }} - {{- end }} - spec: - {{- if .Values.schedulerName }} - schedulerName: "{{ .Values.schedulerName }}" - {{- end }} - {{- if .Values.priorityClassName }} - priorityClassName: {{ .Values.priorityClassName }} - {{- end }} - {{- if .Values.securityContext.enabled }} - securityContext: - fsGroup: {{ .Values.securityContext.fsGroup }} - {{- end }} - {{- if .Values.affinity }} - affinity: -{{ toYaml .Values.affinity | indent 8 }} - {{- end -}} - {{- if .Values.nodeSelector }} - nodeSelector: -{{ toYaml .Values.nodeSelector | indent 8 }} - {{- end }} - {{- if .Values.tolerations }} - tolerations: -{{ toYaml .Values.tolerations | indent 8 }} - {{- end }} -{{- include "mongodb.imagePullSecrets" . | indent 6 }} - initContainers: - {{- if .Values.extraInitContainers }} -{{ tpl .Values.extraInitContainers . | indent 6}} - {{- end }} - {{- if and .Values.volumePermissions.enabled .Values.persistence.enabled }} - - name: volume-permissions - image: {{ template "mongodb.volumePermissions.image" . }} - imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} - command: ["chown", "-R", "{{ .Values.securityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }}", "{{ .Values.persistence.mountPath }}"] - securityContext: - runAsUser: 0 - resources: {{ toYaml .Values.volumePermissions.resources | nindent 10 }} - volumeMounts: - - name: datadir - mountPath: {{ .Values.persistence.mountPath }} - {{- end }} - containers: - - name: {{ template "mongodb.name" . }}-primary - image: {{ template "mongodb.image" . }} - imagePullPolicy: {{ .Values.image.pullPolicy }} - {{- if .Values.securityContext.enabled }} - securityContext: - runAsNonRoot: true - runAsUser: {{ .Values.securityContext.runAsUser }} - {{- end }} - ports: - - containerPort: {{ .Values.service.port }} - name: mongodb - env: - {{- if .Values.image.debug}} - - name: BITNAMI_DEBUG - value: "true" - {{- end }} - - name: MONGODB_SYSTEM_LOG_VERBOSITY - value: {{ .Values.mongodbSystemLogVerbosity | quote }} - - name: MONGODB_DISABLE_SYSTEM_LOG - {{- if .Values.mongodbDisableSystemLog }} - value: "yes" - {{- else }} - value: "no" - {{- end }} - - name: MONGODB_POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: MONGODB_REPLICA_SET_MODE - value: "primary" - - name: MONGODB_REPLICA_SET_NAME - value: {{ .Values.replicaSet.name | quote }} - {{- if .Values.replicaSet.useHostnames }} - - name: MONGODB_ADVERTISED_HOSTNAME - value: "$(MONGODB_POD_NAME).{{ template "mongodb.fullname" . }}-headless.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }}" - {{- end }} - {{- if .Values.mongodbUsername }} - - name: MONGODB_USERNAME - value: {{ .Values.mongodbUsername | quote }} - {{- end }} - {{- if .Values.mongodbDatabase }} - - name: MONGODB_DATABASE - value: {{ .Values.mongodbDatabase | quote }} - {{- end }} - {{- if .Values.usePassword }} - {{- if and .Values.mongodbUsername .Values.mongodbDatabase }} - - name: MONGODB_PASSWORD - valueFrom: - secretKeyRef: - name: {{ if .Values.existingSecret }}{{ .Values.existingSecret }}{{- else }}{{ template "mongodb.fullname" . }}{{- end }} - key: mongodb-password - {{- end }} - - name: MONGODB_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: {{ if .Values.existingSecret }}{{ .Values.existingSecret }}{{- else }}{{ template "mongodb.fullname" . }}{{- end }} - key: mongodb-root-password - - name: MONGODB_REPLICA_SET_KEY - valueFrom: - secretKeyRef: - name: {{ if .Values.existingSecret }}{{ .Values.existingSecret }}{{- else }}{{ template "mongodb.fullname" . }}{{- end }} - key: mongodb-replica-set-key - {{- end }} - - name: MONGODB_ENABLE_IPV6 - {{- if .Values.mongodbEnableIPv6 }} - value: "yes" - {{- else }} - value: "no" - {{- end }} - - name: MONGODB_ENABLE_DIRECTORY_PER_DB - {{- if .Values.mongodbDirectoryPerDB }} - value: "yes" - {{- else }} - value: "no" - {{- end }} - {{- if .Values.mongodbExtraFlags }} - - name: MONGODB_EXTRA_FLAGS - value: {{ .Values.mongodbExtraFlags | join " " | quote }} - {{- end }} - {{- if .Values.extraEnvVars }} - {{- include "mongodb.tplValue" ( dict "value" .Values.extraEnvVars "context" $ ) | nindent 10 }} - {{- end }} - {{- if .Values.livenessProbe.enabled }} - livenessProbe: - exec: - command: - - pgrep - - mongod - initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.livenessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} - successThreshold: {{ .Values.livenessProbe.successThreshold }} - failureThreshold: {{ .Values.livenessProbe.failureThreshold }} - {{- end }} - {{- if .Values.readinessProbe.enabled }} - readinessProbe: - exec: - command: - - mongo - - --eval - - "db.adminCommand('ping')" - initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.readinessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} - successThreshold: {{ .Values.readinessProbe.successThreshold }} - failureThreshold: {{ .Values.readinessProbe.failureThreshold }} - {{- end }} - volumeMounts: - - name: datadir - mountPath: {{ .Values.persistence.mountPath }} - subPath: {{ .Values.persistence.subPath }} - {{- if or (.Files.Glob "files/docker-entrypoint-initdb.d/*[sh|js|json]") (.Values.initConfigMap) }} - - name: custom-init-scripts - mountPath: /docker-entrypoint-initdb.d - {{- end }} - {{- if .Values.configmap }} - - name: config - mountPath: /opt/bitnami/mongodb/conf/mongodb.conf - subPath: mongodb.conf - {{- end }} - {{- if .Values.extraVolumeMounts }} -{{ toYaml .Values.extraVolumeMounts | indent 12}} - {{- end }} - resources: -{{ toYaml .Values.resources | indent 12 }} -{{- if .Values.metrics.enabled }} - - name: metrics - image: {{ template "mongodb.metrics.image" . }} - imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} - {{- if .Values.securityContext.enabled }} - securityContext: - runAsNonRoot: true - runAsUser: {{ .Values.securityContext.runAsUser }} - {{- end }} - env: - {{- if .Values.usePassword }} - - name: MONGODB_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: {{ if .Values.existingSecret }}{{ .Values.existingSecret }}{{- else }}{{ template "mongodb.fullname" . }}{{- end }} - key: mongodb-root-password - command: [ 'sh', '-c', '/bin/mongodb_exporter --mongodb.uri mongodb://root:${MONGODB_ROOT_PASSWORD}@localhost:{{ .Values.service.port }}/admin {{ .Values.metrics.extraArgs }}' ] - {{- else }} - command: [ 'sh', '-c', '/bin/mongodb_exporter --mongodb.uri mongodb://localhost:{{ .Values.service.port }} {{ .Values.metrics.extraArgs }}' ] - {{- end }} - ports: - - name: metrics - containerPort: 9216 - {{- if .Values.metrics.livenessProbe.enabled }} - livenessProbe: - httpGet: - path: /metrics - port: metrics - initialDelaySeconds: {{ .Values.metrics.livenessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.metrics.livenessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.metrics.livenessProbe.timeoutSeconds }} - failureThreshold: {{ .Values.metrics.livenessProbe.failureThreshold }} - successThreshold: {{ .Values.metrics.livenessProbe.successThreshold }} - {{- end }} - {{- if .Values.metrics.readinessProbe.enabled }} - readinessProbe: - httpGet: - path: /metrics - port: metrics - initialDelaySeconds: {{ .Values.metrics.readinessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.metrics.readinessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.metrics.readinessProbe.timeoutSeconds }} - failureThreshold: {{ .Values.metrics.readinessProbe.failureThreshold }} - successThreshold: {{ .Values.metrics.readinessProbe.successThreshold }} - {{- end }} - resources: -{{ toYaml .Values.metrics.resources | indent 12 }} -{{- end }} -{{- if .Values.sidecars }} -{{ toYaml .Values.sidecars | indent 8 }} -{{- end }} - volumes: - {{- if (.Files.Glob "files/docker-entrypoint-initdb.d/*[sh|js|json]") }} - - name: custom-init-scripts - configMap: - name: {{ template "mongodb.fullname" . }}-init-scripts - {{- end }} - {{- if (.Values.initConfigMap) }} - - name: custom-init-scripts - configMap: - name: {{ .Values.initConfigMap.name }} - {{- end }} - {{- if .Values.configmap }} - - name: config - configMap: - name: {{ template "mongodb.fullname" . }} - {{- end }} - {{- if .Values.extraVolumes }} -{{ toYaml .Values.extraVolumes | indent 8}} - {{- end }} -{{- if .Values.persistence.enabled }} - volumeClaimTemplates: - - metadata: - name: datadir - annotations: - {{- range $key, $value := .Values.persistence.annotations }} - {{ $key }}: "{{ $value }}" - {{- end }} - spec: - accessModes: - {{- range .Values.persistence.accessModes }} - - {{ . | quote }} - {{- end }} - resources: - requests: - storage: {{ .Values.persistence.size | quote }} - {{ include "mongodb.storageClass" . }} -{{- else }} - - name: datadir - emptyDir: {} -{{- end }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/statefulset-secondary-rs.yaml b/deployment/deployment/middleware_deployment/mongodb/templates/statefulset-secondary-rs.yaml deleted file mode 100644 index 0b94e90..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/statefulset-secondary-rs.yaml +++ /dev/null @@ -1,281 +0,0 @@ -{{- if .Values.replicaSet.enabled }} -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: {{ template "mongodb.fullname" . }}-secondary - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - {{- with .Values.labels }} -{{ toYaml . | indent 4 }} - {{- end }} - {{- with .Values.annotations }} - annotations: -{{ toYaml . | indent 4 }} - {{- end }} -spec: - selector: - matchLabels: - app: {{ template "mongodb.name" . }} - release: {{ .Release.Name }} - component: secondary - podManagementPolicy: "Parallel" - serviceName: {{ template "mongodb.fullname" . }}-headless - replicas: {{ .Values.replicaSet.replicas.secondary }} - updateStrategy: - type: {{ .Values.updateStrategy.type }} - {{- if (eq "Recreate" .Values.updateStrategy.type) }} - rollingUpdate: null - {{- end }} - template: - metadata: - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - release: {{ .Release.Name }} - component: secondary - {{- if .Values.podLabels }} -{{ toYaml .Values.podLabels | indent 8 }} - {{- end }} - {{- if or .Values.podAnnotations .Values.metrics.enabled }} - annotations: -{{- if .Values.podAnnotations }} -{{ toYaml .Values.podAnnotations | indent 8 }} -{{- end }} -{{- if .Values.metrics.enabled }} -{{ toYaml .Values.metrics.podAnnotations | indent 8 }} -{{- end }} - {{- end }} - spec: - {{- if .Values.schedulerName }} - schedulerName: "{{ .Values.schedulerName }}" - {{- end }} - {{- if .Values.priorityClassName }} - priorityClassName: {{ .Values.priorityClassName }} - {{- end }} - {{- if .Values.securityContext.enabled }} - securityContext: - fsGroup: {{ .Values.securityContext.fsGroup }} - {{- end }} - {{- if .Values.affinity }} - affinity: -{{ toYaml .Values.affinity | indent 8 }} - {{- end -}} - {{- if .Values.nodeSelector }} - nodeSelector: -{{ toYaml .Values.nodeSelector | indent 8 }} - {{- end }} - {{- if .Values.tolerations }} - tolerations: -{{ toYaml .Values.tolerations | indent 8 }} - {{- end }} -{{- include "mongodb.imagePullSecrets" . | indent 6 }} - initContainers: - {{- if .Values.extraInitContainers }} -{{ tpl .Values.extraInitContainers . | indent 6}} - {{- end }} - {{- if and .Values.volumePermissions.enabled .Values.persistence.enabled }} - - name: volume-permissions - image: {{ template "mongodb.volumePermissions.image" . }} - imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} - command: ["chown", "-R", "{{ .Values.securityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }}", "{{ .Values.persistence.mountPath }}"] - securityContext: - runAsUser: 0 - resources: {{ toYaml .Values.volumePermissions.resources | nindent 10 }} - volumeMounts: - - name: datadir - mountPath: {{ .Values.persistence.mountPath }} - {{- end }} - containers: - - name: {{ template "mongodb.name" . }}-secondary - image: {{ template "mongodb.image" . }} - imagePullPolicy: {{ .Values.image.pullPolicy }} - {{- if .Values.securityContext.enabled }} - securityContext: - runAsNonRoot: true - runAsUser: {{ .Values.securityContext.runAsUser }} - {{- end }} - ports: - - containerPort: {{ .Values.service.port }} - name: mongodb - env: - {{- if .Values.image.debug}} - - name: BITNAMI_DEBUG - value: "true" - {{- end }} - - name: MONGODB_SYSTEM_LOG_VERBOSITY - value: {{ .Values.mongodbSystemLogVerbosity | quote }} - - name: MONGODB_DISABLE_SYSTEM_LOG - {{- if .Values.mongodbDisableSystemLog }} - value: "yes" - {{- else }} - value: "no" - {{- end }} - - name: MONGODB_POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: MONGODB_REPLICA_SET_MODE - value: "secondary" - - name: MONGODB_PRIMARY_HOST - value: {{ template "mongodb.fullname" . }} - - name: MONGODB_REPLICA_SET_NAME - value: {{ .Values.replicaSet.name | quote }} - {{- if .Values.replicaSet.useHostnames }} - - name: MONGODB_ADVERTISED_HOSTNAME - value: "$(MONGODB_POD_NAME).{{ template "mongodb.fullname" . }}-headless.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }}" - {{- end }} - {{- if .Values.usePassword }} - - name: MONGODB_PRIMARY_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: {{ if .Values.existingSecret }}{{ .Values.existingSecret }}{{- else }}{{ template "mongodb.fullname" . }}{{- end }} - key: mongodb-root-password - - name: MONGODB_REPLICA_SET_KEY - valueFrom: - secretKeyRef: - name: {{ if .Values.existingSecret }}{{ .Values.existingSecret }}{{- else }}{{ template "mongodb.fullname" . }}{{- end }} - key: mongodb-replica-set-key - {{- end }} - - name: MONGODB_ENABLE_IPV6 - {{- if .Values.mongodbEnableIPv6 }} - value: "yes" - {{- else }} - value: "no" - {{- end }} - - name: MONGODB_ENABLE_DIRECTORY_PER_DB - {{- if .Values.mongodbDirectoryPerDB }} - value: "yes" - {{- else }} - value: "no" - {{- end }} - {{- if .Values.mongodbExtraFlags }} - - name: MONGODB_EXTRA_FLAGS - value: {{ .Values.mongodbExtraFlags | join " " | quote }} - {{- end }} - {{- if .Values.extraEnvVars }} - {{- include "mongodb.tplValue" ( dict "value" .Values.extraEnvVars "context" $ ) | nindent 10 }} - {{- end }} - {{- if .Values.livenessProbe.enabled }} - livenessProbe: - exec: - command: - - pgrep - - mongod - initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.livenessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} - successThreshold: {{ .Values.livenessProbe.successThreshold }} - failureThreshold: {{ .Values.livenessProbe.failureThreshold }} - {{- end }} - {{- if .Values.readinessProbe.enabled }} - readinessProbe: - exec: - command: - - mongo - - --eval - - "db.adminCommand('ping')" - initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.readinessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} - successThreshold: {{ .Values.readinessProbe.successThreshold }} - failureThreshold: {{ .Values.readinessProbe.failureThreshold }} - {{- end }} - volumeMounts: - - name: datadir - mountPath: {{ .Values.persistence.mountPath }} - subPath: {{ .Values.persistence.subPath }} - {{- if .Values.configmap }} - - name: config - mountPath: /opt/bitnami/mongodb/conf/mongodb.conf - subPath: mongodb.conf - {{- end }} - {{- if .Values.extraVolumeMounts }} -{{ toYaml .Values.extraVolumeMounts | indent 12}} - {{- end }} - resources: -{{ toYaml .Values.resources | indent 12 }} -{{- if .Values.metrics.enabled }} - - name: metrics - image: {{ template "mongodb.metrics.image" . }} - imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} - {{- if .Values.securityContext.enabled }} - securityContext: - runAsNonRoot: true - runAsUser: {{ .Values.securityContext.runAsUser }} - {{- end }} - env: - {{- if .Values.usePassword }} - - name: MONGODB_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: {{ if .Values.existingSecret }}{{ .Values.existingSecret }}{{- else }}{{ template "mongodb.fullname" . }}{{- end }} - key: mongodb-root-password - command: [ 'sh', '-c', '/bin/mongodb_exporter --mongodb.uri mongodb://root:${MONGODB_ROOT_PASSWORD}@localhost:{{ .Values.service.port }}/admin {{ .Values.metrics.extraArgs }}' ] - {{- else }} - command: [ 'sh', '-c', '/bin/mongodb_exporter --mongodb.uri mongodb://localhost:{{ .Values.service.port }} {{ .Values.metrics.extraArgs }}' ] - {{- end }} - ports: - - name: metrics - containerPort: 9216 - {{- if .Values.metrics.livenessProbe.enabled }} - livenessProbe: - httpGet: - path: /metrics - port: metrics - initialDelaySeconds: {{ .Values.metrics.livenessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.metrics.livenessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.metrics.livenessProbe.timeoutSeconds }} - failureThreshold: {{ .Values.metrics.livenessProbe.failureThreshold }} - successThreshold: {{ .Values.metrics.livenessProbe.successThreshold }} - {{- end }} - {{- if .Values.metrics.readinessProbe.enabled }} - readinessProbe: - httpGet: - path: /metrics - port: metrics - initialDelaySeconds: {{ .Values.metrics.readinessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.metrics.readinessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.metrics.readinessProbe.timeoutSeconds }} - failureThreshold: {{ .Values.metrics.readinessProbe.failureThreshold }} - successThreshold: {{ .Values.metrics.readinessProbe.successThreshold }} - {{- end }} - resources: -{{ toYaml .Values.metrics.resources | indent 12 }} -{{- end }} -{{- if .Values.sidecars }} -{{ toYaml .Values.sidecars | indent 8 }} -{{- end }} - volumes: - {{- if .Values.configmap }} - - name: config - configMap: - name: {{ template "mongodb.fullname" . }} - {{- end }} - {{- if .Values.extraVolumes }} -{{ toYaml .Values.extraVolumes | indent 8}} - {{- end }} -{{- if .Values.persistence.enabled }} - volumeClaimTemplates: - - metadata: - name: datadir - annotations: - {{- range $key, $value := .Values.persistence.annotations }} - {{ $key }}: "{{ $value }}" - {{- end }} - spec: - accessModes: - {{- range .Values.persistence.accessModes }} - - {{ . | quote }} - {{- end }} - resources: - requests: - storage: {{ .Values.persistence.size | quote }} - {{ include "mongodb.storageClass" . }} -{{- else }} - - name: datadir - emptyDir: {} -{{- end }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/svc-headless-rs.yaml b/deployment/deployment/middleware_deployment/mongodb/templates/svc-headless-rs.yaml deleted file mode 100644 index 92f1141..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/svc-headless-rs.yaml +++ /dev/null @@ -1,23 +0,0 @@ -{{- if .Values.replicaSet.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: {{ template "mongodb.fullname" . }}-headless - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" -{{- with .Values.service.annotations }} - annotations: {{ tpl (toYaml .) $ | nindent 4 }} -{{- end }} -spec: - type: ClusterIP - clusterIP: None - ports: - - name: mongodb - port: {{ .Values.service.port }} - selector: - app: {{ template "mongodb.name" . }} - release: {{ .Release.Name }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/svc-primary-rs.yaml b/deployment/deployment/middleware_deployment/mongodb/templates/svc-primary-rs.yaml deleted file mode 100644 index 7815068..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/svc-primary-rs.yaml +++ /dev/null @@ -1,44 +0,0 @@ -{{- if .Values.replicaSet.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: {{ template "mongodb.serviceName" . }} - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" -{{- with .Values.service.annotations }} - annotations: {{ tpl (toYaml .) $ | nindent 4 }} -{{- end }} -spec: - type: {{ .Values.service.type }} - {{- if and (eq .Values.service.type "ClusterIP") .Values.service.clusterIP }} - clusterIP: {{ .Values.service.clusterIP }} - {{- end }} - {{- if and (eq .Values.service.type "LoadBalancer") .Values.service.loadBalancerIP }} - loadBalancerIP: {{ .Values.service.loadBalancerIP }} - {{- end }} - {{- if .Values.service.externalIPs }} - externalIPs: {{ toYaml .Values.service.externalIPs | nindent 4 }} - {{- end }} - {{- if .Values.service.loadBalancerSourceRanges }} - loadBalancerSourceRanges: {{- toYaml .Values.service.loadBalancerSourceRanges | nindent 4 }} - {{- end }} - ports: - - name: mongodb - port: {{ .Values.service.port }} - targetPort: mongodb -{{- if .Values.service.nodePort }} - nodePort: {{ .Values.service.nodePort }} -{{- end }} -{{- if .Values.metrics.enabled }} - - name: metrics - port: 9216 - targetPort: metrics -{{- end }} - selector: - app: {{ template "mongodb.name" . }} - release: "{{ .Release.Name }}" - component: primary -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mongodb/templates/svc-standalone.yaml b/deployment/deployment/middleware_deployment/mongodb/templates/svc-standalone.yaml deleted file mode 100644 index 0695c73..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/templates/svc-standalone.yaml +++ /dev/null @@ -1,43 +0,0 @@ -{{- if not .Values.replicaSet.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: {{ template "mongodb.serviceName" . }} - labels: - app: {{ template "mongodb.name" . }} - chart: {{ template "mongodb.chart" . }} - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" -{{- with .Values.service.annotations }} - annotations: {{ tpl (toYaml .) $ | nindent 4 }} -{{- end }} -spec: - type: {{ .Values.service.type }} - {{- if and (eq .Values.service.type "ClusterIP") .Values.service.clusterIP }} - clusterIP: {{ .Values.service.clusterIP }} - {{- end }} - {{- if and (eq .Values.service.type "LoadBalancer") .Values.service.loadBalancerIP }} - loadBalancerIP: {{ .Values.service.loadBalancerIP }} - {{- end }} - {{- if .Values.service.externalIPs }} - externalIPs: {{ toYaml .Values.service.externalIPs | nindent 4 }} - {{- end }} - {{- if .Values.service.loadBalancerSourceRanges }} - loadBalancerSourceRanges: {{- toYaml .Values.service.loadBalancerSourceRanges | nindent 4 }} - {{- end }} - ports: - - name: mongodb - port: {{ .Values.service.port }} - targetPort: mongodb -{{- if .Values.service.nodePort }} - nodePort: {{ .Values.service.nodePort }} -{{- end }} -{{- if .Values.metrics.enabled }} - - name: metrics - port: 9216 - targetPort: metrics -{{- end }} - selector: - app: {{ template "mongodb.name" . }} - release: "{{ .Release.Name }}" -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mongodb/values-production.yaml b/deployment/deployment/middleware_deployment/mongodb/values-production.yaml deleted file mode 100644 index f2c31ed..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/values-production.yaml +++ /dev/null @@ -1,506 +0,0 @@ -## 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 and imagePullSecrets -## -# global: -# imageRegistry: myRegistryName -# imagePullSecrets: -# - myRegistryKeySecretName -# storageClass: myStorageClass - -image: - ## Bitnami MongoDB registry - ## - registry: docker.io - ## Bitnami MongoDB image name - ## - repository: bitnami/mongodb - ## Bitnami MongoDB image tag - ## ref: https://hub.docker.com/r/bitnami/mongodb/tags/ - ## - tag: 4.2.4-debian-10-r0 - ## Specify a imagePullPolicy - ## ref: http://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/ - ## - # pullSecrets: - # - myRegistryKeySecretName - - ## Set to true if you would like to see extra information on logs - ## It turns on Bitnami debugging in minideb-extras-base - ## ref: https://github.com/bitnami/minideb-extras-base - debug: false - -## String to partially override mongodb.fullname template (will maintain the release name) -## -# nameOverride: - -## String to fully override mongodb.fullname template -## -# fullnameOverride: - -# Add custom extra environment variables to all the MongoDB containers -# extraEnvVars: - -## Init containers parameters: -## volumePermissions: Change the owner and group of the persistent volume mountpoint to runAsUser:fsGroup values from the securityContext section. -## -volumePermissions: - enabled: false - image: - registry: docker.io - repository: bitnami/minideb - tag: buster - pullPolicy: Always - ## 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/ - ## - # pullSecrets: - # - myRegistryKeySecretName - resources: {} - -## Enable authentication -## ref: https://docs.mongodb.com/manual/tutorial/enable-authentication/ -# -usePassword: true -# existingSecret: name-of-existing-secret - -## MongoDB admin password -## ref: https://github.com/bitnami/bitnami-docker-mongodb/blob/master/README.md#setting-the-root-password-on-first-run -## -# mongodbRootPassword: - -## MongoDB custom user and database -## ref: https://github.com/bitnami/bitnami-docker-mongodb/blob/master/README.md#creating-a-user-and-database-on-first-run -## -# mongodbUsername: username -# mongodbPassword: password -# mongodbDatabase: database - -## Whether enable/disable IPv6 on MongoDB -## ref: https://github.com/bitnami/bitnami-docker-mongodb/blob/master/README.md#enabling/disabling-ipv6 -## -mongodbEnableIPv6: false - -## Whether enable/disable DirectoryPerDB on MongoDB -## ref: https://github.com/bitnami/bitnami-docker-mongodb/blob/master/README.md#enabling/disabling-directoryperdb -## -mongodbDirectoryPerDB: false - -## MongoDB System Log configuration -## ref: https://github.com/bitnami/bitnami-docker-mongodb#configuring-system-log-verbosity-level -## -mongodbSystemLogVerbosity: 0 -mongodbDisableSystemLog: false - -## MongoDB additional command line flags -## -## Can be used to specify command line flags, for example: -## -## mongodbExtraFlags: -## - "--wiredTigerCacheSizeGB=2" -mongodbExtraFlags: [] - -## Pod Security Context -## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ -## -securityContext: - enabled: true - fsGroup: 1001 - runAsUser: 1001 - -## Kubernetes Cluster Domain -clusterDomain: cluster.local - -## Kubernetes service type -service: - ## Specify an explicit service name. - # name: svc-mongo - ## Provide any additional annotations which may be required. - ## The value is evaluated as a template, so, for example, the value can depend on .Release or .Chart - annotations: {} - type: ClusterIP - # clusterIP: None - port: 27017 - - ## Specify the nodePort value for the LoadBalancer and NodePort service types. - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport - ## - # nodePort: - - ## Specify the externalIP value ClusterIP service type. - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#external-ips - # externalIPs: [] - - ## Specify the loadBalancerIP value for LoadBalancer service types. - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer - ## - # loadBalancerIP: - - ## Specify the loadBalancerSourceRanges value for LoadBalancer service types. - ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service - ## - # loadBalancerSourceRanges: [] - -## Use StatefulSet instead of Deployment when deploying standalone -useStatefulSet: false - -## Setting up replication -## ref: https://github.com/bitnami/bitnami-docker-mongodb#setting-up-a-replication -# -replicaSet: - ## Whether to create a MongoDB replica set for high availability or not - enabled: true - useHostnames: true - - ## Name of the replica set - ## - name: rs0 - - ## Key used for replica set authentication - ## - # key: key - - ## Number of replicas per each node type - ## - replicas: - secondary: 1 - arbiter: 1 - - ## Pod Disruption Budget - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ - pdb: - enabled: true - minAvailable: - secondary: 1 - arbiter: 1 - # maxUnavailable: - # secondary: 1 - # arbiter: 1 - -# Annotations to be added to the deployment or statefulsets -annotations: {} - -# Additional labels to apply to the deployment or statefulsets -labels: {} - -# Annotations to be added to MongoDB pods -podAnnotations: {} - -# Additional pod labels to apply -podLabels: {} - -## Use an alternate scheduler, e.g. "stork". -## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ -## -# schedulerName: - -## Configure resource requests and limits -## ref: http://kubernetes.io/docs/user-guide/compute-resources/ -## -resources: {} -# Define separate resources per arbiter, which are less then primary or secondary -# used only when replica set is enabled -resourcesArbiter: {} -# limits: -# cpu: 500m -# memory: 512Mi -# requests: -# cpu: 100m -# memory: 256Mi - -## Pod priority -## https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ -# priorityClassName: "" - -## Node selector -## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector -nodeSelector: {} - -## Affinity -## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity -affinity: {} -# Define separate affinity for arbiter pod -affinityArbiter: {} - -## Tolerations -## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ -tolerations: [] - -## Add sidecars to the pod -## -## For example: -## sidecars: -## - name: your-image-name -## image: your-image -## imagePullPolicy: Always -## ports: -## - name: portname -## containerPort: 1234 -sidecars: [] -## Array to add extra volumes -## -extraVolumes: [] -## Array to add extra mounts (normally used with extraVolumes) -## -extraVolumeMounts: [] - -## Add sidecars to the arbiter pod -# used only when replica set is enabled -## -## For example: -## sidecars: -## - name: your-image-name -## image: your-image -## imagePullPolicy: Always -## ports: -## - name: portname -## containerPort: 1234 -sidecarsArbiter: [] -## Array to add extra volumes to the arbiter -# used only when replica set is enabled -## -extraVolumesArbiter: [] -## Array to add extra mounts (normally used with extraVolumes) to the arbiter -# used only when replica set is enabled -## -extraVolumeMountsArbiter: [] - -## updateStrategy for MongoDB Primary, Secondary and Arbitrer statefulsets -## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies -updateStrategy: - type: RollingUpdate - -## Enable persistence using Persistent Volume Claims -## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/ -## -persistence: - enabled: true - ## A manually managed Persistent Volume and Claim - ## Requires persistence.enabled: true - ## If defined, PVC must be created manually before volume will be bound - ## - # existingClaim: - - ## The path the volume will be mounted at, useful when using different - ## MongoDB images. - ## - mountPath: /bitnami/mongodb - - ## The subdirectory of the volume to mount to, useful in dev environments - ## and one PV for multiple services. - ## - subPath: "" - - ## mongodb data 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: "-" - accessModes: - - ReadWriteOnce - size: 8Gi - annotations: {} - -## Configure the ingress resource that allows you to access the -## MongoDB installation. Set up the URL -## ref: http://kubernetes.io/docs/user-guide/ingress/ -## -ingress: - ## Set to true to enable ingress record generation - enabled: false - - ## Set this to true in order to add the corresponding annotations for cert-manager - certManager: false - - ## Ingress annotations done as key:value pairs - ## For a full list of possible ingress annotations, please see - ## ref: https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/annotations.md - ## - ## If tls is set to true, annotation ingress.kubernetes.io/secure-backends: "true" will automatically be set - ## If certManager is set to true, annotation kubernetes.io/tls-acme: "true" will automatically be set - annotations: - # kubernetes.io/ingress.class: nginx - - ## The list of hostnames to be covered with this ingress record. - ## Most likely this will be just one host, but in the event more hosts are needed, this is an array - hosts: - - name: mongodb.local - path: / - - ## The tls configuration for the ingress - ## see: https://kubernetes.io/docs/concepts/services-networking/ingress/#tls - tls: - - hosts: - - mongodb.local - secretName: mongodb.local-tls - - secrets: - ## If you're providing your own certificates, please use this to add the certificates as secrets - ## key and certificate should start with -----BEGIN CERTIFICATE----- or - ## -----BEGIN RSA PRIVATE KEY----- - ## - ## name should line up with a tlsSecret set further up - ## If you're using cert-manager, this is unneeded, as it will create the secret for you if it is not set - ## - ## It is also possible to create and manage the certificates outside of this helm chart - ## Please see README.md for more information - # - name: airflow.local-tls - # key: - # certificate: - -## Configure the options for init containers to be run before the main app containers -## are started. All init containers are run sequentially and must exit without errors -## for the next one to be started. -## ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ -# extraInitContainers: | -# - name: do-something -# image: busybox -# command: ['do', 'something'] - -## Configure extra options for liveness and readiness probes -## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) -livenessProbe: - enabled: true - initialDelaySeconds: 30 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 -readinessProbe: - enabled: true - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 - -# Define custom config map with init scripts -initConfigMap: {} -# name: "init-config-map" - -## Entries for the MongoDB config file. For documentation of all options, see: -## http://docs.mongodb.org/manual/reference/configuration-options/ -## -configmap: -# # where and how to store data. -# storage: -# dbPath: /bitnami/mongodb/data/db -# journal: -# enabled: true -# directoryPerDB: false -# # where to write logging data. -# systemLog: -# destination: file -# quiet: false -# logAppend: true -# logRotate: reopen -# path: /opt/bitnami/mongodb/logs/mongodb.log -# verbosity: 0 -# # network interfaces -# net: -# port: 27017 -# unixDomainSocket: -# enabled: true -# pathPrefix: /opt/bitnami/mongodb/tmp -# ipv6: false -# bindIpAll: true -# # replica set options -# #replication: -# #replSetName: replicaset -# #enableMajorityReadConcern: true -# # process management options -# processManagement: -# fork: false -# pidFilePath: /opt/bitnami/mongodb/tmp/mongodb.pid -# # set parameter options -# setParameter: -# enableLocalhostAuthBypass: true -# # security options -# security: -# authorization: disabled -# #keyFile: /opt/bitnami/mongodb/conf/keyfile - -## Prometheus Exporter / Metrics -## -metrics: - enabled: true - - image: - registry: docker.io - repository: bitnami/mongodb-exporter - tag: 0.10.0-debian-10-r41 - 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/ - ## - # pullSecrets: - # - myRegistryKeySecretName - - ## String with extra arguments to the metrics exporter - ## ref: https://github.com/percona/mongodb_exporter/blob/master/mongodb_exporter.go - extraArgs: "" - - ## Metrics exporter resource requests and limits - ## ref: http://kubernetes.io/docs/user-guide/compute-resources/ - ## - # resources: {} - - ## Metrics exporter liveness and readiness probes - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) - livenessProbe: - enabled: true - initialDelaySeconds: 15 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 3 - successThreshold: 1 - readinessProbe: - enabled: true - initialDelaySeconds: 5 - periodSeconds: 5 - timeoutSeconds: 1 - failureThreshold: 3 - successThreshold: 1 - - ## Metrics exporter pod Annotation - podAnnotations: - prometheus.io/scrape: "true" - prometheus.io/port: "9216" - - ## Prometheus Service Monitor - ## ref: https://github.com/coreos/prometheus-operator - ## https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md - serviceMonitor: - ## If the operator is installed in your cluster, set to true to create a Service Monitor Entry - enabled: false - - ## Specify a namespace if needed - # namespace: monitoring - - ## Used to pass Labels that are used by the Prometheus installed in your cluster to select Service Monitors to work with - ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#prometheusspec - additionalLabels: {} - - ## Specify Metric Relabellings to add to the scrape endpoint - ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#endpoint - # relabellings: - - alerting: - ## Define individual alerting rules as required - ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#rulegroup - ## https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/ - rules: {} - - ## Used to pass Labels that are used by the Prometheus installed in your cluster to select Prometheus Rules to work with - ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#prometheusspec - additionalLabels: {} diff --git a/deployment/deployment/middleware_deployment/mongodb/values.schema.json b/deployment/deployment/middleware_deployment/mongodb/values.schema.json deleted file mode 100644 index 9bf39e5..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/values.schema.json +++ /dev/null @@ -1,147 +0,0 @@ -{ - "$schema": "http://json-schema.org/schema#", - "type": "object", - "properties": { - "usePassword": { - "type": "boolean", - "title": "Enable password authentication", - "form": true - }, - "mongodbRootPassword": { - "type": "string", - "title": "MongoDB admin password", - "form": true, - "description": "Defaults to a random 10-character alphanumeric string if not set", - "hidden": { - "condition": false, - "value": "usePassword" - } - }, - "mongodbDatabase": { - "type": "string", - "title": "MongoDB custom database", - "description": "Name of the custom database to be created during the 1st initialization of MongoDB", - "form": true - }, - "mongodbUsername": { - "type": "string", - "title": "MongoDB custom user", - "description": "Name of the custom user to be created during the 1st initialization of MongoDB. This user only has permissions on the MongoDB custom database", - "form": true - }, - "mongodbPassword": { - "type": "string", - "title": "Password for MongoDB custom user", - "form": true, - "description": "Defaults to a random 10-character alphanumeric string if not set", - "hidden": { - "condition": false, - "value": "usePassword" - } - }, - "replicaSet": { - "type": "object", - "title": "Replicaset configuration", - "form": true, - "properties": { - "enabled": { - "type": "boolean", - "form": true, - "title": "Enable replicaset configuration" - }, - "replicas": { - "type": "object", - "title": "Number of replicas", - "form": true, - "hidden": { - "condition": false, - "value": "replicaSet.enabled" - }, - "properties": { - "secondary": { - "type": "integer", - "title": "Secondary node replicas", - "description": "Number of secondary node replicas to deploy", - "form": true - }, - "arbiter": { - "type": "integer", - "title": "Arbiter node replicas", - "description": "Number of arbiter node replicas to deploy", - "form": true - } - } - } - } - }, - "persistence": { - "type": "object", - "title": "Persistence configuration", - "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": { - "condition": false, - "value": "persistence.enabled" - } - } - } - }, - "volumePermissions": { - "type": "object", - "hidden": { - "condition": false, - "value": "persistence.enabled" - }, - "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": { - "condition": false, - "value": "metrics.enabled" - } - } - } - } - } - } - } -} diff --git a/deployment/deployment/middleware_deployment/mongodb/values.yaml b/deployment/deployment/middleware_deployment/mongodb/values.yaml deleted file mode 100644 index 51ffd1b..0000000 --- a/deployment/deployment/middleware_deployment/mongodb/values.yaml +++ /dev/null @@ -1,508 +0,0 @@ -## 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 and imagePullSecrets -## -# global: -# imageRegistry: myRegistryName -# imagePullSecrets: -# - myRegistryKeySecretName -# storageClass: myStorageClass - -image: - ## Bitnami MongoDB registry - ## - registry: docker.io - ## Bitnami MongoDB image name - ## - repository: bitnami/mongodb - ## Bitnami MongoDB image tag - ## ref: https://hub.docker.com/r/bitnami/mongodb/tags/ - ## - tag: 4.2.4-debian-10-r0 - ## Specify a imagePullPolicy - ## ref: http://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/ - ## - # pullSecrets: - # - myRegistryKeySecretName - - ## Set to true if you would like to see extra information on logs - ## It turns on Bitnami debugging in minideb-extras-base - ## ref: https://github.com/bitnami/minideb-extras-base - debug: false - -## String to partially override mongodb.fullname template (will maintain the release name) -## -# nameOverride: - -## String to fully override mongodb.fullname template -## -# fullnameOverride: - -## Init containers parameters: -## volumePermissions: Change the owner and group of the persistent volume mountpoint to runAsUser:fsGroup values from the securityContext section. -## -volumePermissions: - enabled: false - image: - registry: docker.io - repository: bitnami/minideb - tag: buster - pullPolicy: Always - ## 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/ - ## - # pullSecrets: - # - myRegistryKeySecretName - resources: {} - -## Enable authentication -## ref: https://docs.mongodb.com/manual/tutorial/enable-authentication/ -# -usePassword: true -# existingSecret: name-of-existing-secret - -## MongoDB admin password -## ref: https://github.com/bitnami/bitnami-docker-mongodb/blob/master/README.md#setting-the-root-password-on-first-run -## -mongodbRootPassword: qxp1234 - -## MongoDB custom user and database -## ref: https://github.com/bitnami/bitnami-docker-mongodb/blob/master/README.md#creating-a-user-and-database-on-first-run -## -#mongodbUsername: qxp -#mongodbPassword: qxp1234 -#mongodbDatabase: admin - -## Whether enable/disable IPv6 on MongoDB -## ref: https://github.com/bitnami/bitnami-docker-mongodb/blob/master/README.md#enabling/disabling-ipv6 -## -mongodbEnableIPv6: false - -## Whether enable/disable DirectoryPerDB on MongoDB -## ref: https://github.com/bitnami/bitnami-docker-mongodb/blob/master/README.md#enabling/disabling-directoryperdb -## -mongodbDirectoryPerDB: false - -## MongoDB System Log configuration -## ref: https://github.com/bitnami/bitnami-docker-mongodb#configuring-system-log-verbosity-level -## -mongodbSystemLogVerbosity: 0 -mongodbDisableSystemLog: false - -## MongoDB additional command line flags -## -## Can be used to specify command line flags, for example: -## -## mongodbExtraFlags: -## - "--wiredTigerCacheSizeGB=2" -mongodbExtraFlags: [] - -## Pod Security Context -## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ -## -securityContext: - enabled: true - fsGroup: 1001 - runAsUser: 1001 - -## Kubernetes Cluster Domain -clusterDomain: cluster.local - -## Kubernetes service type -service: - ## Specify an explicit service name. - # name: svc-mongo - ## Provide any additional annotations which may be required. - ## The value is evaluated as a template, so, for example, the value can depend on .Release or .Chart - annotations: {} - type: NodePort - # clusterIP: None - port: 27017 - - ## Specify the nodePort value for the LoadBalancer and NodePort service types. - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport - ## - # nodePort: - - ## Specify the externalIP value ClusterIP service type. - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#external-ips - # externalIPs: [] - - ## Specify the loadBalancerIP value for LoadBalancer service types. - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer - ## - # loadBalancerIP: - - ## Specify the loadBalancerSourceRanges value for LoadBalancer service types. - ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service - ## - # loadBalancerSourceRanges: [] - -# Add custom extra environment variables to all the MongoDB containers -# extraEnvVars: - -## Use StatefulSet instead of Deployment when deploying standalone -useStatefulSet: false - -## Setting up replication -## ref: https://github.com/bitnami/bitnami-docker-mongodb#setting-up-a-replication -# -replicaSet: - ## Whether to create a MongoDB replica set for high availability or not - enabled: false - useHostnames: true - - ## Name of the replica set - ## - name: rs0 - - ## Key used for replica set authentication - ## - # key: key - - ## Number of replicas per each node type - ## - replicas: - secondary: 1 - arbiter: 1 - - ## Pod Disruption Budget - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ - pdb: - enabled: true - minAvailable: - primary: 1 - secondary: 1 - arbiter: 1 - # maxUnavailable: - # primary: 1 - # secondary: 1 - # arbiter: 1 - -# Annotations to be added to the deployment or statefulsets -annotations: {} - -# Additional labels to apply to the deployment or statefulsets -labels: {} - -# Annotations to be added to MongoDB pods -podAnnotations: {} - -# Additional pod labels to apply -podLabels: {} - -## Use an alternate scheduler, e.g. "stork". -## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ -## -# schedulerName: - -## Configure resource requests and limits -## ref: http://kubernetes.io/docs/user-guide/compute-resources/ -## -resources: {} -# Define separate resources per arbiter, which are less then primary or secondary -# used only when replica set is enabled -resourcesArbiter: {} -# limits: -# cpu: 500m -# memory: 512Mi -# requests: -# cpu: 100m -# memory: 256Mi - -## Pod priority -## https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ -# priorityClassName: "" - -## Node selector -## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector -nodeSelector: {} - -## Affinity -## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity -affinity: {} -# Define separate affinity for arbiter pod -affinityArbiter: {} - -## Tolerations -## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ -tolerations: [] - -## updateStrategy for MongoDB Primary, Secondary and Arbitrer statefulsets -## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies -updateStrategy: - type: RollingUpdate - -## Add sidecars to the pod -## -## For example: -## sidecars: -## - name: your-image-name -## image: your-image -## imagePullPolicy: Always -## ports: -## - name: portname -## containerPort: 1234 -sidecars: [] -## Array to add extra volumes -## -extraVolumes: [] -## Array to add extra mounts (normally used with extraVolumes) -## -extraVolumeMounts: [] - -## Add sidecars to the arbiter pod -# used only when replica set is enabled -## -## For example: -## sidecars: -## - name: your-image-name -## image: your-image -## imagePullPolicy: Always -## ports: -## - name: portname -## containerPort: 1234 -sidecarsArbiter: [] -## Array to add extra volumes to the arbiter -# used only when replica set is enabled -## -extraVolumesArbiter: [] -## Array to add extra mounts (normally used with extraVolumes) to the arbiter -# used only when replica set is enabled -## -extraVolumeMountsArbiter: [] - -## Enable persistence using Persistent Volume Claims -## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/ -## -persistence: - enabled: true - ## A manually managed Persistent Volume and Claim - ## Requires persistence.enabled: true - ## If defined, PVC must be created manually before volume will be bound - ## - # existingClaim: - - ## The path the volume will be mounted at, useful when using different - ## MongoDB images. - ## - mountPath: /bitnami/mongodb - - ## The subdirectory of the volume to mount to, useful in dev environments - ## and one PV for multiple services. - ## - subPath: "" - - ## mongodb data 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: "" - accessModes: - - ReadWriteOnce - size: 10Gi - annotations: {} - -## Configure the ingress resource that allows you to access the -## MongoDB installation. Set up the URL -## ref: http://kubernetes.io/docs/user-guide/ingress/ -## -ingress: - ## Set to true to enable ingress record generation - enabled: false - - ## Set this to true in order to add the corresponding annotations for cert-manager - certManager: false - - ## Ingress annotations done as key:value pairs - ## For a full list of possible ingress annotations, please see - ## ref: https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/annotations.md - ## - ## If tls is set to true, annotation ingress.kubernetes.io/secure-backends: "true" will automatically be set - ## If certManager is set to true, annotation kubernetes.io/tls-acme: "true" will automatically be set - annotations: - # kubernetes.io/ingress.class: nginx - - ## The list of hostnames to be covered with this ingress record. - ## Most likely this will be just one host, but in the event more hosts are needed, this is an array - hosts: - - name: mongodb.local - path: / - - ## The tls configuration for the ingress - ## see: https://kubernetes.io/docs/concepts/services-networking/ingress/#tls - tls: - - hosts: - - mongodb.local - secretName: mongodb.local-tls - - secrets: - ## If you're providing your own certificates, please use this to add the certificates as secrets - ## key and certificate should start with -----BEGIN CERTIFICATE----- or - ## -----BEGIN RSA PRIVATE KEY----- - ## - ## name should line up with a tlsSecret set further up - ## If you're using cert-manager, this is unneeded, as it will create the secret for you if it is not set - ## - ## It is also possible to create and manage the certificates outside of this helm chart - ## Please see README.md for more information - # - name: airflow.local-tls - # key: - # certificate: - -## Configure the options for init containers to be run before the main app containers -## are started. All init containers are run sequentially and must exit without errors -## for the next one to be started. -## ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ -# extraInitContainers: | -# - name: do-something -# image: busybox -# command: ['do', 'something'] - -## Configure extra options for liveness and readiness probes -## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) -livenessProbe: - enabled: true - initialDelaySeconds: 30 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 -readinessProbe: - enabled: true - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 - -# Define custom config map with init scripts -initConfigMap: {} -# name: "init-config-map" - -## Entries for the MongoDB config file. For documentation of all options, see: -## http://docs.mongodb.org/manual/reference/configuration-options/ -## -configmap: -# # where and how to store data. -# storage: -# dbPath: /bitnami/mongodb/data/db -# journal: -# enabled: true -# directoryPerDB: false -# # where to write logging data. -# systemLog: -# destination: file -# quiet: false -# logAppend: true -# logRotate: reopen -# path: /opt/bitnami/mongodb/logs/mongodb.log -# verbosity: 0 -# # network interfaces -# net: -# port: 27017 -# unixDomainSocket: -# enabled: true -# pathPrefix: /opt/bitnami/mongodb/tmp -# ipv6: false -# bindIpAll: true -# # replica set options -# #replication: -# #replSetName: replicaset -# #enableMajorityReadConcern: true -# # process management options -# processManagement: -# fork: false -# pidFilePath: /opt/bitnami/mongodb/tmp/mongodb.pid -# # set parameter options -# setParameter: -# enableLocalhostAuthBypass: true -# # security options -# security: -# authorization: disabled -# #keyFile: /opt/bitnami/mongodb/conf/keyfile - -## Prometheus Exporter / Metrics -## -metrics: - enabled: false - - image: - registry: docker.io - repository: bitnami/mongodb-exporter - tag: 0.10.0-debian-10-r41 - 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/ - ## - # pullSecrets: - # - myRegistryKeySecretName - - ## String with extra arguments to the metrics exporter - ## ref: https://github.com/percona/mongodb_exporter/blob/master/mongodb_exporter.go - extraArgs: "" - - ## Metrics exporter resource requests and limits - ## ref: http://kubernetes.io/docs/user-guide/compute-resources/ - ## - # resources: {} - - ## Metrics exporter liveness and readiness probes - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) - livenessProbe: - enabled: false - initialDelaySeconds: 15 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 3 - successThreshold: 1 - readinessProbe: - enabled: false - initialDelaySeconds: 5 - periodSeconds: 5 - timeoutSeconds: 1 - failureThreshold: 3 - successThreshold: 1 - - ## Metrics exporter pod Annotation - podAnnotations: - prometheus.io/scrape: "true" - prometheus.io/port: "9216" - - ## Prometheus Service Monitor - ## ref: https://github.com/coreos/prometheus-operator - ## https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md - serviceMonitor: - ## If the operator is installed in your cluster, set to true to create a Service Monitor Entry - enabled: false - - ## Specify a namespace if needed - # namespace: monitoring - - ## Used to pass Labels that are used by the Prometheus installed in your cluster to select Service Monitors to work with - ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#prometheusspec - additionalLabels: {} - - ## Specify Metric Relabellings to add to the scrape endpoint - ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#endpoint - # relabellings: - - alerting: - ## Define individual alerting rules as required - ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#rulegroup - ## https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/ - rules: {} - - ## Used to pass Labels that are used by the Prometheus installed in your cluster to select Prometheus Rules to work with - ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#prometheusspec - additionalLabels: {} diff --git a/deployment/deployment/middleware_deployment/mysql/.helmignore b/deployment/deployment/middleware_deployment/mysql/.helmignore deleted file mode 100644 index a1c17ae..0000000 --- a/deployment/deployment/middleware_deployment/mysql/.helmignore +++ /dev/null @@ -1,2 +0,0 @@ -.git -OWNERS \ No newline at end of file diff --git a/deployment/deployment/middleware_deployment/mysql/Chart.yaml b/deployment/deployment/middleware_deployment/mysql/Chart.yaml deleted file mode 100755 index 5bca632..0000000 --- a/deployment/deployment/middleware_deployment/mysql/Chart.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: v1 -name: mysql -version: 1.6.9 -appVersion: 5.7.30 -description: DEPRECATED - Fast, reliable, scalable, and easy to use open-source relational database - system. -keywords: -- mysql -- database -- sql -home: https://www.mysql.com/ -icon: https://www.mysql.com/common/logos/logo-mysql-170x115.png -sources: -- https://github.com/kubernetes/charts -- https://github.com/docker-library/mysql -deprecated: true -engine: gotpl diff --git a/deployment/deployment/middleware_deployment/mysql/README.md b/deployment/deployment/middleware_deployment/mysql/README.md deleted file mode 100755 index 6923e2a..0000000 --- a/deployment/deployment/middleware_deployment/mysql/README.md +++ /dev/null @@ -1,255 +0,0 @@ -# ⚠️ Repo Archive Notice - -As of Nov 13, 2020, charts in this repo will no longer be updated. -For more information, see the Helm Charts [Deprecation and Archive Notice](https://github.com/helm/charts#%EF%B8%8F-deprecation-and-archive-notice), and [Update](https://helm.sh/blog/charts-repo-deprecation/). - -# MySQL - -[MySQL](https://MySQL.org) is one of the most popular database servers in the world. Notable users include Wikipedia, Facebook and Google. - -## DEPRECATION NOTICE - -This chart is deprecated and no longer supported. - -## Introduction - -This chart bootstraps a single node MySQL deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. - -## Prerequisites - -- Kubernetes 1.10+ with Beta APIs enabled -- PV provisioner support in the underlying infrastructure - -## Installing the Chart - -To install the chart with the release name `my-release`: - -```bash -$ helm install --name my-release stable/mysql -``` - -The command deploys MySQL on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation. - -By default a random password will be generated for the root user. If you'd like to set your own password change the mysqlRootPassword -in the values.yaml. - -You can retrieve your root password by running the following command. Make sure to replace [YOUR_RELEASE_NAME]: - - printf $(printf '\%o' `kubectl get secret [YOUR_RELEASE_NAME]-mysql -o jsonpath="{.data.mysql-root-password[*]}"`) - -> **Tip**: List all releases using `helm list` - -## Uninstalling the Chart - -To uninstall/delete the `my-release` deployment: - -```bash -$ helm delete --purge my-release -``` - -The command removes all the Kubernetes components associated with the chart and deletes the release completely. - -## Configuration - -The following table lists the configurable parameters of the MySQL chart and their default values. - -| Parameter | Description | Default | -| -------------------------------------------- | -------------------------------------------------------------------------------------------- | ---------------------------------------------------- | -| `args` | Additional arguments to pass to the MySQL container. | `[]` | -| `initContainer.resources` | initContainer resource requests/limits | Memory: `10Mi`, CPU: `10m` | -| `image` | `mysql` image repository. | `mysql` | -| `imageTag` | `mysql` image tag. | `5.7.30` | -| `busybox.image` | `busybox` image repository. | `busybox` | -| `busybox.tag` | `busybox` image tag. | `1.32` | -| `testFramework.enabled` | `test-framework` switch. | `true` | -| `testFramework.image` | `test-framework` image repository. | `bats/bats` | -| `testFramework.tag` | `test-framework` image tag. | `1.2.1` | -| `testFramework.imagePullPolicy` | `test-framework` image pull policy. | `IfNotPresent` | -| `testFramework.securityContext` | `test-framework` securityContext | `{}` | -| `imagePullPolicy` | Image pull policy | `IfNotPresent` | -| `existingSecret` | Use Existing secret for Password details | `nil` | -| `extraVolumes` | Additional volumes as a string to be passed to the `tpl` function | | -| `extraVolumeMounts` | Additional volumeMounts as a string to be passed to the `tpl` function | | -| `extraInitContainers` | Additional init containers as a string to be passed to the `tpl` function | | -| `extraEnvVars` | Additional environment variables as a string to be passed to the `tpl` function | | -| `mysqlRootPassword` | Password for the `root` user. Ignored if existing secret is provided | Random 10 characters | -| `mysqlUser` | Username of new user to create. | `nil` | -| `mysqlPassword` | Password for the new user. Ignored if existing secret is provided | Random 10 characters | -| `mysqlDatabase` | Name for new database to create. | `nil` | -| `livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 30 | -| `livenessProbe.periodSeconds` | How often to perform the probe | 10 | -| `livenessProbe.timeoutSeconds` | When the probe times out | 5 | -| `livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed. | 1 | -| `livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 3 | -| `readinessProbe.initialDelaySeconds` | Delay before readiness probe is initiated | 5 | -| `readinessProbe.periodSeconds` | How often to perform the probe | 10 | -| `readinessProbe.timeoutSeconds` | When the probe times out | 1 | -| `readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed. | 1 | -| `readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 3 | -| `schedulerName` | Name of the k8s scheduler (other than default) | `nil` | -| `mysqlx.port.enabled` | Boolean to toggle a port for mysqlx `33060` protocol. | false | -| `persistence.enabled` | Create a volume to store data | true | -| `persistence.size` | Size of persistent volume claim | 8Gi RW | -| `persistence.storageClass` | Type of persistent volume claim | nil | -| `persistence.accessMode` | ReadWriteOnce or ReadOnly | ReadWriteOnce | -| `persistence.existingClaim` | Name of existing persistent volume | `nil` | -| `persistence.subPath` | Subdirectory of the volume to mount | `nil` | -| `persistence.annotations` | Persistent Volume annotations | {} | -| `nodeSelector` | Node labels for pod assignment | {} | -| `affinity` | Affinity rules for pod assignment | {} | -| `tolerations` | Pod taint tolerations for deployment | {} | -| `metrics.enabled` | Start a side-car prometheus exporter | `false` | -| `metrics.image` | Exporter image | `prom/mysqld-exporter` | -| `metrics.imageTag` | Exporter image | `v0.10.0` | -| `metrics.imagePullPolicy` | Exporter image pull policy | `IfNotPresent` | -| `metrics.resources` | Exporter resource requests/limit | `nil` | -| `metrics.livenessProbe.initialDelaySeconds` | Delay before metrics liveness probe is initiated | 15 | -| `metrics.livenessProbe.timeoutSeconds` | When the probe times out | 5 | -| `metrics.readinessProbe.initialDelaySeconds` | Delay before metrics readiness probe is initiated | 5 | -| `metrics.readinessProbe.timeoutSeconds` | When the probe times out | 1 | -| `metrics.flags` | Additional flags for the mysql exporter to use | `[]` | -| `metrics.serviceMonitor.enabled` | Set this to `true` to create ServiceMonitor for Prometheus operator | `false` | -| `metrics.serviceMonitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | `{}` | -| `resources` | CPU/Memory resource requests/limits | Memory: `256Mi`, CPU: `100m` | -| `configurationFiles` | List of mysql configuration files | `nil` | -| `configurationFilesPath` | Path of mysql configuration files | `/etc/mysql/conf.d/` | -| `securityContext.enabled` | Enable security context (mysql pod) | `false` | -| `securityContext.fsGroup` | Group ID for the container (mysql pod) | 999 | -| `securityContext.runAsUser` | User ID for the container (mysql pod) | 999 | -| `service.annotations` | Kubernetes annotations for mysql | {} | -| `service.type` | Kubernetes service type | ClusterIP | -| `service.loadBalancerIP` | LoadBalancer service IP | `""` | -| `serviceAccount.create` | Specifies whether a ServiceAccount should be created | `false` | -| `serviceAccount.name` | The name of the ServiceAccount to create | Generated using the mysql.fullname template | -| `ssl.enabled` | Setup and use SSL for MySQL connections | `false` | -| `ssl.secret` | Name of the secret containing the SSL certificates | mysql-ssl-certs | -| `ssl.certificates[0].name` | Name of the secret containing the SSL certificates | `nil` | -| `ssl.certificates[0].ca` | CA certificate | `nil` | -| `ssl.certificates[0].cert` | Server certificate (public key) | `nil` | -| `ssl.certificates[0].key` | Server key (private key) | `nil` | -| `imagePullSecrets` | Name of Secret resource containing private registry credentials | `nil` | -| `initializationFiles` | List of SQL files which are run after the container started | `nil` | -| `timezone` | Container and mysqld timezone (TZ env) | `nil` (UTC depending on image) | -| `podAnnotations` | Map of annotations to add to the pods | `{}` | -| `podLabels` | Map of labels to add to the pods | `{}` | -| `priorityClassName` | Set pod priorityClassName | `{}` | -| `deploymentAnnotations` | Map of annotations for deployment | `{}` | -| `strategy` | Update strategy policy | `{type: "Recreate"}` | - -Some of the parameters above map to the env variables defined in the [MySQL DockerHub image](https://hub.docker.com/_/mysql/). - -Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, - -```bash -$ helm install --name my-release \ - --set mysqlRootPassword=secretpassword,mysqlUser=my-user,mysqlPassword=my-password,mysqlDatabase=my-database \ - stable/mysql -``` - -The above command sets the MySQL `root` account password to `secretpassword`. Additionally it creates a standard database user named `my-user`, with the password `my-password`, who has access to a database named `my-database`. - -Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, - -```bash -$ helm install --name my-release -f values.yaml stable/mysql -``` - -> **Tip**: You can use the default [values.yaml](values.yaml) - -## Persistence - -The [MySQL](https://hub.docker.com/_/mysql/) image stores the MySQL data and configurations at the `/var/lib/mysql` path of the container. - -By default a PersistentVolumeClaim is created and mounted into that directory. In order to disable this functionality -you can change the values.yaml to disable persistence and use an emptyDir instead. - -> *"An emptyDir volume is first created when a Pod is assigned to a Node, and exists as long as that Pod is running on that node. When a Pod is removed from a node for any reason, the data in the emptyDir is deleted forever."* - -**Notice**: You may need to increase the value of `livenessProbe.initialDelaySeconds` when enabling persistence by using PersistentVolumeClaim from PersistentVolume with varying properties. Since its IO performance has impact on the database initialization performance. The default limit for database initialization is `60` seconds (`livenessProbe.initialDelaySeconds` + `livenessProbe.periodSeconds` * `livenessProbe.failureThreshold`). Once such initialization process takes more time than this limit, kubelet will restart the database container, which will interrupt database initialization then causing persisent data in an unusable state. - -## Custom MySQL configuration files - -The [MySQL](https://hub.docker.com/_/mysql/) image accepts custom configuration files at the path `/etc/mysql/conf.d`. If you want to use a customized MySQL configuration, you can create your alternative configuration files by passing the file contents on the `configurationFiles` attribute. Note that according to the MySQL documentation only files ending with `.cnf` are loaded. - -```yaml -configurationFiles: - mysql.cnf: |- - [mysqld] - skip-host-cache - skip-name-resolve - sql-mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION - mysql_custom.cnf: |- - [mysqld] -``` - -## MySQL initialization files - -The [MySQL](https://hub.docker.com/_/mysql/) image accepts *.sh, *.sql and *.sql.gz files at the path `/docker-entrypoint-initdb.d`. -These files are being run exactly once for container initialization and ignored on following container restarts. -If you want to use initialization scripts, you can create initialization files by passing the file contents on the `initializationFiles` attribute. - - -```yaml -initializationFiles: - first-db.sql: |- - CREATE DATABASE IF NOT EXISTS first DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; - second-db.sql: |- - CREATE DATABASE IF NOT EXISTS second DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; -``` - -## SSL - -This chart supports configuring MySQL to use [encrypted connections](https://dev.mysql.com/doc/refman/5.7/en/encrypted-connections.html) with TLS/SSL certificates provided by the user. This is accomplished by storing the required Certificate Authority file, the server public key certificate, and the server private key as a Kubernetes secret. The SSL options for this chart support the following use cases: - -* Manage certificate secrets with helm -* Manage certificate secrets outside of helm - -## Manage certificate secrets with helm - -Include your certificate data in the `ssl.certificates` section. For example: - -``` -ssl: - enabled: false - secret: mysql-ssl-certs - certificates: - - name: mysql-ssl-certs - ca: |- - -----BEGIN CERTIFICATE----- - ... - -----END CERTIFICATE----- - cert: |- - -----BEGIN CERTIFICATE----- - ... - -----END CERTIFICATE----- - key: |- - -----BEGIN RSA PRIVATE KEY----- - ... - -----END RSA PRIVATE KEY----- -``` - -> **Note**: Make sure your certificate data has the correct formatting in the values file. - -## Manage certificate secrets outside of helm - -1. Ensure the certificate secret exist before installation of this chart. -2. Set the name of the certificate secret in `ssl.secret`. -3. Make sure there are no entries underneath `ssl.certificates`. - -To manually create the certificate secret from local files you can execute: -``` -kubectl create secret generic mysql-ssl-certs \ - --from-file=ca.pem=./ssl/certificate-authority.pem \ - --from-file=server-cert.pem=./ssl/server-public-key.pem \ - --from-file=server-key.pem=./ssl/server-private-key.pem -``` -> **Note**: `ca.pem`, `server-cert.pem`, and `server-key.pem` **must** be used as the key names in this generic secret. - -If you are using a certificate your configurationFiles must include the three ssl lines under [mysqld] - -``` -[mysqld] - ssl-ca=/ssl/ca.pem - ssl-cert=/ssl/server-cert.pem - ssl-key=/ssl/server-key.pem -``` diff --git a/deployment/deployment/middleware_deployment/mysql/templates/NOTES.txt b/deployment/deployment/middleware_deployment/mysql/templates/NOTES.txt deleted file mode 100644 index 864170c..0000000 --- a/deployment/deployment/middleware_deployment/mysql/templates/NOTES.txt +++ /dev/null @@ -1,48 +0,0 @@ -MySQL can be accessed via port 3306 on the following DNS name from within your cluster: -{{ template "mysql.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local - -{{- if .Values.mysqlx.port.enabled }} -Connection to the X protocol of MySQL can be done via 33060 on the following DNS name from within your cluster: -{{ template "mysql.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local -{{- end }} - -{{- if .Values.existingSecret }} -If you have not already created the mysql password secret: - - kubectl create secret generic {{ .Values.existingSecret }} --namespace {{ .Release.Namespace }} --from-file=./mysql-root-password --from-file=./mysql-password -{{ else }} - -To get your root password run: - - MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "mysql.fullname" . }} -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo) -{{- end }} - -To connect to your database: - -1. Run an Ubuntu pod that you can use as a client: - - kubectl run -i --tty ubuntu --image=ubuntu:16.04 --restart=Never -- bash -il - -2. Install the mysql client: - - $ apt-get update && apt-get install mysql-client -y - -3. Connect using the mysql cli, then provide your password: - $ mysql -h {{ template "mysql.fullname" . }} -p - -To connect to your database directly from outside the K8s cluster: - {{- if contains "NodePort" .Values.service.type }} - MYSQL_HOST=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath='{.items[0].status.addresses[0].address}') - MYSQL_PORT=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "mysql.fullname" . }} -o jsonpath='{.spec.ports[0].nodePort}') - - {{- else if contains "ClusterIP" .Values.service.type }} - MYSQL_HOST=127.0.0.1 - MYSQL_PORT={{ .Values.service.port }} - - # Execute the following command to route the connection: - kubectl port-forward svc/{{ template "mysql.fullname" . }} {{ .Values.service.port }} - - {{- end }} - - mysql -h ${MYSQL_HOST} -P${MYSQL_PORT} -u root -p${MYSQL_ROOT_PASSWORD} - diff --git a/deployment/deployment/middleware_deployment/mysql/templates/_helpers.tpl b/deployment/deployment/middleware_deployment/mysql/templates/_helpers.tpl deleted file mode 100644 index f108425..0000000 --- a/deployment/deployment/middleware_deployment/mysql/templates/_helpers.tpl +++ /dev/null @@ -1,43 +0,0 @@ -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "mysql.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 "mysql.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- printf .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Generate chart secret name -*/}} -{{- define "mysql.secretName" -}} -{{ default (include "mysql.fullname" .) .Values.existingSecret }} -{{- end -}} - -{{/* -Create the name of the service account to use -*/}} -{{- define "mysql.serviceAccountName" -}} -{{- if .Values.serviceAccount.create -}} -{{ default (include "mysql.fullname" .) .Values.serviceAccount.name }} -{{- else -}} -{{ default "default" .Values.serviceAccount.name }} -{{- end -}} -{{- end -}} diff --git a/deployment/deployment/middleware_deployment/mysql/templates/configurationFiles-configmap.yaml b/deployment/deployment/middleware_deployment/mysql/templates/configurationFiles-configmap.yaml deleted file mode 100644 index ebed8cc..0000000 --- a/deployment/deployment/middleware_deployment/mysql/templates/configurationFiles-configmap.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.configurationFiles }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "mysql.fullname" . }}-configuration - namespace: {{ .Release.Namespace }} -data: -{{- range $key, $val := .Values.configurationFiles }} - {{ $key }}: |- -{{ $val | indent 4}} -{{- end }} -{{- end -}} \ No newline at end of file diff --git a/deployment/deployment/middleware_deployment/mysql/templates/deployment.yaml b/deployment/deployment/middleware_deployment/mysql/templates/deployment.yaml deleted file mode 100644 index 94f94b0..0000000 --- a/deployment/deployment/middleware_deployment/mysql/templates/deployment.yaml +++ /dev/null @@ -1,259 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ template "mysql.fullname" . }} - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "mysql.fullname" . }} - chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" -{{- with .Values.deploymentAnnotations }} - annotations: -{{ toYaml . | indent 4 }} -{{- end }} - -spec: - strategy: -{{ toYaml .Values.strategy | indent 4 }} - selector: - matchLabels: - app: {{ template "mysql.fullname" . }} - release: {{ .Release.Name }} - template: - metadata: - labels: - app: {{ template "mysql.fullname" . }} - release: {{ .Release.Name }} -{{- with .Values.podLabels }} -{{ toYaml . | indent 8 }} -{{- end }} -{{- with .Values.podAnnotations }} - annotations: -{{ toYaml . | indent 8 }} -{{- end }} - spec: - {{- if .Values.schedulerName }} - schedulerName: "{{ .Values.schedulerName }}" - {{- end }} - {{- if .Values.imagePullSecrets }} - imagePullSecrets: -{{ toYaml .Values.imagePullSecrets | indent 8 }} - {{- end }} - {{- if .Values.priorityClassName }} - priorityClassName: "{{ .Values.priorityClassName }}" - {{- end }} - {{- if .Values.securityContext.enabled }} - securityContext: - fsGroup: {{ .Values.securityContext.fsGroup }} - runAsUser: {{ .Values.securityContext.runAsUser }} - {{- end }} - serviceAccountName: {{ template "mysql.serviceAccountName" . }} - initContainers: - - name: "remove-lost-found" - image: "{{ .Values.busybox.image}}:{{ .Values.busybox.tag }}" - imagePullPolicy: {{ .Values.imagePullPolicy | quote }} - resources: -{{ toYaml .Values.initContainer.resources | indent 10 }} - command: ["rm", "-fr", "/var/lib/mysql/lost+found"] - volumeMounts: - - name: data - mountPath: /var/lib/mysql - {{- if .Values.persistence.subPath }} - subPath: {{ .Values.persistence.subPath }} - {{- end }} - {{- if .Values.extraInitContainers }} -{{ tpl .Values.extraInitContainers . | indent 6 }} - {{- end }} - {{- if .Values.nodeSelector }} - nodeSelector: -{{ toYaml .Values.nodeSelector | indent 8 }} - {{- end }} - {{- if .Values.affinity }} - affinity: -{{ toYaml .Values.affinity | indent 8 }} - {{- end }} - {{- if .Values.tolerations }} - tolerations: -{{ toYaml .Values.tolerations | indent 8 }} - {{- end }} - containers: - - name: {{ template "mysql.fullname" . }} - image: "{{ .Values.image }}:{{ .Values.imageTag }}" - imagePullPolicy: {{ .Values.imagePullPolicy | quote }} - - {{- with .Values.args }} - args: - {{- range . }} - - {{ . | quote }} - {{- end }} - {{- end }} - resources: -{{ toYaml .Values.resources | indent 10 }} - env: - {{- if .Values.mysqlAllowEmptyPassword }} - - name: MYSQL_ALLOW_EMPTY_PASSWORD - value: "true" - {{- end }} - {{- if not (and .Values.allowEmptyRootPassword (not .Values.mysqlRootPassword)) }} - - name: MYSQL_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "mysql.secretName" . }} - key: mysql-root-password - {{- if .Values.mysqlAllowEmptyPassword }} - optional: true - {{- end }} - {{- end }} - {{- if not (and .Values.allowEmptyRootPassword (not .Values.mysqlPassword)) }} - - name: MYSQL_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "mysql.secretName" . }} - key: mysql-password - {{- if or .Values.mysqlAllowEmptyPassword (empty .Values.mysqlUser) }} - optional: true - {{- end }} - {{- end }} - - name: MYSQL_USER - value: {{ default "" .Values.mysqlUser | quote }} - - name: MYSQL_DATABASE - value: {{ default "" .Values.mysqlDatabase | quote }} - {{- if .Values.timezone }} - - name: TZ - value: {{ .Values.timezone }} - {{- end }} - {{- if .Values.extraEnvVars }} -{{ tpl .Values.extraEnvVars . | indent 8 }} - {{- end }} - ports: - - name: mysql - containerPort: 3306 - {{- if .Values.mysqlx.port.enabled }} - - name: mysqlx - port: 33060 - {{- end }} - livenessProbe: - exec: - command: - {{- if .Values.mysqlAllowEmptyPassword }} - - mysqladmin - - ping - {{- else }} - - sh - - -c - - "mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}" - {{- end }} - initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.livenessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} - successThreshold: {{ .Values.livenessProbe.successThreshold }} - failureThreshold: {{ .Values.livenessProbe.failureThreshold }} - readinessProbe: - exec: - command: - {{- if .Values.mysqlAllowEmptyPassword }} - - mysqladmin - - ping - {{- else }} - - sh - - -c - - "mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}" - {{- end }} - initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.readinessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} - successThreshold: {{ .Values.readinessProbe.successThreshold }} - failureThreshold: {{ .Values.readinessProbe.failureThreshold }} - volumeMounts: - - name: data - mountPath: /var/lib/mysql - {{- if .Values.persistence.subPath }} - subPath: {{ .Values.persistence.subPath }} - {{- end }} - {{- if .Values.configurationFiles }} - {{- range $key, $val := .Values.configurationFiles }} - - name: configurations - mountPath: {{ $.Values.configurationFilesPath }}{{ $key }} - subPath: {{ $key }} - {{- end -}} - {{- end }} - {{- if .Values.initializationFiles }} - - name: migrations - mountPath: /docker-entrypoint-initdb.d - {{- end }} - {{- if .Values.ssl.enabled }} - - name: certificates - mountPath: /ssl - {{- end }} - {{- if .Values.extraVolumeMounts }} -{{ tpl .Values.extraVolumeMounts . | indent 8 }} - {{- end }} - {{- if .Values.metrics.enabled }} - - name: metrics - image: "{{ .Values.metrics.image }}:{{ .Values.metrics.imageTag }}" - imagePullPolicy: {{ .Values.metrics.imagePullPolicy | quote }} - {{- if .Values.mysqlAllowEmptyPassword }} - command: - - 'sh' - - '-c' - - 'DATA_SOURCE_NAME="root@(localhost:3306)/" /bin/mysqld_exporter' - {{- else }} - env: - - name: MYSQL_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "mysql.secretName" . }} - key: mysql-root-password - command: - - 'sh' - - '-c' - - 'DATA_SOURCE_NAME="root:$MYSQL_ROOT_PASSWORD@(localhost:3306)/" /bin/mysqld_exporter' - {{- end }} - {{- range $f := .Values.metrics.flags }} - - {{ $f | quote }} - {{- end }} - ports: - - name: metrics - containerPort: 9104 - livenessProbe: - httpGet: - path: / - port: metrics - initialDelaySeconds: {{ .Values.metrics.livenessProbe.initialDelaySeconds }} - timeoutSeconds: {{ .Values.metrics.livenessProbe.timeoutSeconds }} - readinessProbe: - httpGet: - path: / - port: metrics - initialDelaySeconds: {{ .Values.metrics.readinessProbe.initialDelaySeconds }} - timeoutSeconds: {{ .Values.metrics.readinessProbe.timeoutSeconds }} - resources: -{{ toYaml .Values.metrics.resources | indent 10 }} - {{- end }} - volumes: - {{- if .Values.configurationFiles }} - - name: configurations - configMap: - name: {{ template "mysql.fullname" . }}-configuration - {{- end }} - {{- if .Values.initializationFiles }} - - name: migrations - configMap: - name: {{ template "mysql.fullname" . }}-initialization - {{- end }} - {{- if .Values.ssl.enabled }} - - name: certificates - secret: - secretName: {{ .Values.ssl.secret }} - {{- end }} - - name: data - {{- if .Values.persistence.enabled }} - persistentVolumeClaim: - claimName: {{ .Values.persistence.existingClaim | default (include "mysql.fullname" .) }} - {{- else }} - emptyDir: {} - {{- end -}} - {{- if .Values.extraVolumes }} -{{ tpl .Values.extraVolumes . | indent 6 }} - {{- end }} diff --git a/deployment/deployment/middleware_deployment/mysql/templates/initializationFiles-configmap.yaml b/deployment/deployment/middleware_deployment/mysql/templates/initializationFiles-configmap.yaml deleted file mode 100644 index 38c3795..0000000 --- a/deployment/deployment/middleware_deployment/mysql/templates/initializationFiles-configmap.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.initializationFiles }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "mysql.fullname" . }}-initialization - namespace: {{ .Release.Namespace }} -data: -{{- range $key, $val := .Values.initializationFiles }} - {{ $key }}: |- -{{ $val | indent 4}} -{{- end }} -{{- end -}} \ No newline at end of file diff --git a/deployment/deployment/middleware_deployment/mysql/templates/pvc.yaml b/deployment/deployment/middleware_deployment/mysql/templates/pvc.yaml deleted file mode 100644 index 39e9bf8..0000000 --- a/deployment/deployment/middleware_deployment/mysql/templates/pvc.yaml +++ /dev/null @@ -1,29 +0,0 @@ -{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} -kind: PersistentVolumeClaim -apiVersion: v1 -metadata: - name: {{ template "mysql.fullname" . }} - namespace: {{ .Release.Namespace }} -{{- with .Values.persistence.annotations }} - annotations: -{{ toYaml . | indent 4 }} -{{- end }} - labels: - app: {{ template "mysql.fullname" . }} - chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" -spec: - accessModes: - - {{ .Values.persistence.accessMode | quote }} - resources: - requests: - storage: {{ .Values.persistence.size | quote }} -{{- if .Values.persistence.storageClass }} -{{- if (eq "-" .Values.persistence.storageClass) }} - storageClassName: "" -{{- else }} - storageClassName: "{{ .Values.persistence.storageClass }}" -{{- end }} -{{- end }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mysql/templates/secrets.yaml b/deployment/deployment/middleware_deployment/mysql/templates/secrets.yaml deleted file mode 100755 index d9dfd12..0000000 --- a/deployment/deployment/middleware_deployment/mysql/templates/secrets.yaml +++ /dev/null @@ -1,51 +0,0 @@ -{{- if not .Values.existingSecret }} -{{- if or (not .Values.allowEmptyRootPassword) (or .Values.mysqlRootPassword .Values.mysqlPassword) }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ template "mysql.fullname" . }} - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "mysql.fullname" . }} - chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" -type: Opaque -data: - {{ if .Values.mysqlRootPassword }} - mysql-root-password: {{ .Values.mysqlRootPassword | b64enc | quote }} - {{ else }} - {{ if not .Values.allowEmptyRootPassword }} - mysql-root-password: {{ randAlphaNum 10 | b64enc | quote }} - {{ end }} - {{ end }} - {{ if .Values.mysqlPassword }} - mysql-password: {{ .Values.mysqlPassword | b64enc | quote }} - {{ else }} - {{ if not .Values.allowEmptyRootPassword }} - mysql-password: {{ randAlphaNum 10 | b64enc | quote }} - {{ end }} - {{ end }} -{{ end }} -{{- if .Values.ssl.enabled }} -{{ if .Values.ssl.certificates }} -{{- range .Values.ssl.certificates }} ---- -apiVersion: v1 -kind: Secret -metadata: - name: {{ .name }} - labels: - app: {{ template "mysql.fullname" $ }} - chart: "{{ $.Chart.Name }}-{{ $.Chart.Version }}" - release: "{{ $.Release.Name }}" - heritage: "{{ $.Release.Service }}" -type: Opaque -data: - ca.pem: {{ .ca | b64enc }} - server-cert.pem: {{ .cert | b64enc }} - server-key.pem: {{ .key | b64enc }} -{{- end }} -{{- end }} -{{- end }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mysql/templates/serviceaccount.yaml b/deployment/deployment/middleware_deployment/mysql/templates/serviceaccount.yaml deleted file mode 100644 index 36ce6b3..0000000 --- a/deployment/deployment/middleware_deployment/mysql/templates/serviceaccount.yaml +++ /dev/null @@ -1,11 +0,0 @@ -{{- if .Values.serviceAccount.create }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ template "mysql.serviceAccountName" . }} - labels: - app: {{ template "mysql.fullname" . }} - chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mysql/templates/servicemonitor.yaml b/deployment/deployment/middleware_deployment/mysql/templates/servicemonitor.yaml deleted file mode 100644 index bd830be..0000000 --- a/deployment/deployment/middleware_deployment/mysql/templates/servicemonitor.yaml +++ /dev/null @@ -1,26 +0,0 @@ -{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: {{ include "mysql.fullname" . }} - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "mysql.fullname" . }} - chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" - {{- if .Values.metrics.serviceMonitor.additionalLabels }} -{{ toYaml .Values.metrics.serviceMonitor.additionalLabels | indent 4 }} - {{- end }} -spec: - endpoints: - - port: metrics - interval: 30s - namespaceSelector: - matchNames: - - {{ .Release.Namespace }} - selector: - matchLabels: - app: {{ include "mysql.fullname" . }} - release: {{ .Release.Name }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mysql/templates/svc.yaml b/deployment/deployment/middleware_deployment/mysql/templates/svc.yaml deleted file mode 100644 index 3185193..0000000 --- a/deployment/deployment/middleware_deployment/mysql/templates/svc.yaml +++ /dev/null @@ -1,42 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ template "mysql.fullname" . }} - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "mysql.fullname" . }} - chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" - annotations: -{{- if .Values.service.annotations }} -{{ toYaml .Values.service.annotations | indent 4 }} -{{- end }} -{{- if and (.Values.metrics.enabled) (.Values.metrics.annotations) }} -{{ toYaml .Values.metrics.annotations | indent 4 }} -{{- end }} -spec: - type: {{ .Values.service.type }} - {{- if (and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerIP))) }} - loadBalancerIP: {{ .Values.service.loadBalancerIP }} - {{- end }} - ports: - - name: mysql - port: {{ .Values.service.port }} - targetPort: mysql - {{- if .Values.service.nodePort }} - nodePort: {{ .Values.service.nodePort }} - {{- end }} - {{- if .Values.mysqlx.port.enabled }} - - name: mysqlx - port: 33060 - targetPort: mysqlx - protocol: TCP - {{- end }} - {{- if .Values.metrics.enabled }} - - name: metrics - port: 9104 - targetPort: metrics - {{- end }} - selector: - app: {{ template "mysql.fullname" . }} diff --git a/deployment/deployment/middleware_deployment/mysql/templates/tests/test-configmap.yaml b/deployment/deployment/middleware_deployment/mysql/templates/tests/test-configmap.yaml deleted file mode 100644 index ece5a47..0000000 --- a/deployment/deployment/middleware_deployment/mysql/templates/tests/test-configmap.yaml +++ /dev/null @@ -1,23 +0,0 @@ -{{- if .Values.testFramework.enabled }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "mysql.fullname" . }}-test - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "mysql.fullname" . }} - chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - heritage: "{{ .Release.Service }}" - release: "{{ .Release.Name }}" -data: - run.sh: |- - {{- if .Values.ssl.enabled | and .Values.mysqlRootPassword }} - @test "Testing SSL MySQL Connection" { - mysql --host={{ template "mysql.fullname" . }} --port={{ .Values.service.port | default "3306" }} --ssl-cert=/ssl/server-cert.pem --ssl-key=ssl/server-key.pem -u root -p{{ .Values.mysqlRootPassword }} - } - {{- else if .Values.mysqlRootPassword }} - @test "Testing MySQL Connection" { - mysql --host={{ template "mysql.fullname" . }} --port={{ .Values.service.port | default "3306" }} -u root -p{{ .Values.mysqlRootPassword }} - } - {{- end }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mysql/templates/tests/test.yaml b/deployment/deployment/middleware_deployment/mysql/templates/tests/test.yaml deleted file mode 100644 index 1771cd0..0000000 --- a/deployment/deployment/middleware_deployment/mysql/templates/tests/test.yaml +++ /dev/null @@ -1,59 +0,0 @@ -{{- if .Values.testFramework.enabled }} -apiVersion: v1 -kind: Pod -metadata: - name: {{ template "mysql.fullname" . }}-test - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "mysql.fullname" . }} - chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - heritage: "{{ .Release.Service }}" - release: "{{ .Release.Name }}" - annotations: - "helm.sh/hook": test-success -spec: - {{- if .Values.testFramework.securityContext }} - securityContext: {{ toYaml .Values.testFramework.securityContext | nindent 4 }} - {{- end }} - {{- if .Values.imagePullSecrets }} - imagePullSecrets: - {{- range .Values.imagePullSecrets }} - - name: {{ . }} - {{- end}} - {{- end }} - {{- with .Values.nodeSelector }} - nodeSelector: -{{ toYaml . | indent 4 }} - {{- end }} - {{- with .Values.affinity }} - affinity: -{{ toYaml . | indent 4 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: -{{ toYaml . | indent 4 }} - {{- end }} - containers: - - name: {{ .Release.Name }}-test - image: "{{ .Values.testFramework.image }}:{{ .Values.testFramework.tag }}" - imagePullPolicy: "{{ .Values.testFramework.imagePullPolicy}}" - command: ["/opt/bats/bin/bats", "-t", "/tests/run.sh"] - volumeMounts: - - mountPath: /tests - name: tests - readOnly: true - {{- if .Values.ssl.enabled }} - - name: certificates - mountPath: /ssl - {{- end }} - volumes: - - name: tests - configMap: - name: {{ template "mysql.fullname" . }}-test - {{- if .Values.ssl.enabled }} - - name: certificates - secret: - secretName: {{ .Values.ssl.secret }} - {{- end }} - restartPolicy: Never -{{- end }} diff --git a/deployment/deployment/middleware_deployment/mysql/values.yaml b/deployment/deployment/middleware_deployment/mysql/values.yaml deleted file mode 100644 index fdf3c5f..0000000 --- a/deployment/deployment/middleware_deployment/mysql/values.yaml +++ /dev/null @@ -1,247 +0,0 @@ -## mysql image version -## ref: https://hub.docker.com/r/library/mysql/tags/ -## -image: "mysql" -imageTag: "5.7.30" - -strategy: - type: Recreate - -busybox: - image: "busybox" - tag: "1.32" - -testFramework: - enabled: true - image: "bats/bats" - tag: "1.2.1" - imagePullPolicy: IfNotPresent - securityContext: {} - -## Specify password for root user -## -## Default: random 10 character string -mysqlRootPassword: qxp1234 - -## Create a database user -## -#mysqlUser: -## Default: random 10 character string -#mysqlPassword: - -## Allow unauthenticated access, uncomment to enable -## -# mysqlAllowEmptyPassword: true - -## Create a database -## -# mysqlDatabase: - -## Specify an imagePullPolicy (Required) -## It's recommended to change this to 'Always' if the image tag is 'latest' -## ref: http://kubernetes.io/docs/user-guide/images/#updating-images -## -imagePullPolicy: IfNotPresent - -## Additionnal arguments that are passed to the MySQL container. -## For example use --default-authentication-plugin=mysql_native_password if older clients need to -## connect to a MySQL 8 instance. -args: [] - -extraVolumes: | - # - name: extras - # emptyDir: {} - -extraVolumeMounts: | - # - name: extras - # mountPath: /usr/share/extras - # readOnly: true - -extraInitContainers: | - # - name: do-something - # image: busybox - # command: ['do', 'something'] - -## A string to add extra environment variables -# extraEnvVars: | -# - name: EXTRA_VAR -# value: "extra" - -# Optionally specify an array of imagePullSecrets. -# Secrets must be manually created in the namespace. -# ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod -# imagePullSecrets: - # - name: myRegistryKeySecretName - -## Node selector -## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector -nodeSelector: {} - -## Affinity -## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity -affinity: {} - -## Tolerations for pod assignment -## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ -## -tolerations: [] - -livenessProbe: - initialDelaySeconds: 30 - periodSeconds: 10 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 3 - -readinessProbe: - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 1 - successThreshold: 1 - failureThreshold: 3 - -## Persist data to a persistent volume -persistence: - enabled: true - ## database data 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: "" - accessMode: ReadWriteOnce - size: 10Gi - annotations: {} - -## Use an alternate scheduler, e.g. "stork". -## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ -## -# schedulerName: - -## Security context -securityContext: - enabled: false - runAsUser: 999 - fsGroup: 999 - -## Configure resource requests and limits -## ref: http://kubernetes.io/docs/user-guide/compute-resources/ -## -resources: - requests: - memory: 256Mi - cpu: 100m - -# Custom mysql configuration files path -configurationFilesPath: /etc/mysql/conf.d/ - -# Custom mysql configuration files used to override default mysql settings -configurationFiles: {} -# mysql.cnf: |- -# [mysqld] -# skip-name-resolve -# ssl-ca=/ssl/ca.pem -# ssl-cert=/ssl/server-cert.pem -# ssl-key=/ssl/server-key.pem - -# Custom mysql init SQL files used to initialize the database -initializationFiles: {} -# first-db.sql: |- -# CREATE DATABASE IF NOT EXISTS first DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; -# second-db.sql: |- -# CREATE DATABASE IF NOT EXISTS second DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; - -# To enaable the mysql X Protocol's port -# .. will expose the port 33060 -# .. Note the X Plugin needs installation -# ref: https://dev.mysql.com/doc/refman/8.0/en/x-plugin-checking-installation.html -mysqlx: - port: - enabled: false - -metrics: - enabled: false - image: prom/mysqld-exporter - imageTag: v0.10.0 - imagePullPolicy: IfNotPresent - resources: {} - annotations: {} - # prometheus.io/scrape: "true" - # prometheus.io/port: "9104" - livenessProbe: - initialDelaySeconds: 15 - timeoutSeconds: 5 - readinessProbe: - initialDelaySeconds: 5 - timeoutSeconds: 1 - flags: [] - serviceMonitor: - enabled: false - additionalLabels: {} - -## Configure the service -## ref: http://kubernetes.io/docs/user-guide/services/ -service: - annotations: {} - ## Specify a service type - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services---service-types - #type: ClusterIP - type: NodePort - port: 3306 -# nodePort: 32001 - # loadBalancerIP: - -## Pods Service Account -## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ -serviceAccount: - ## Specifies whether a ServiceAccount should be created - ## - create: false - ## The name of the ServiceAccount to use. - ## If not set and create is true, a name is generated using the mariadb.fullname template - # name: - -ssl: - enabled: false - secret: mysql-ssl-certs - certificates: -# - name: mysql-ssl-certs -# ca: |- -# -----BEGIN CERTIFICATE----- -# ... -# -----END CERTIFICATE----- -# cert: |- -# -----BEGIN CERTIFICATE----- -# ... -# -----END CERTIFICATE----- -# key: |- -# -----BEGIN RSA PRIVATE KEY----- -# ... -# -----END RSA PRIVATE KEY----- - -## Populates the 'TZ' system timezone environment variable -## ref: https://dev.mysql.com/doc/refman/5.7/en/time-zone-support.html -## -## Default: nil (mysql will use image's default timezone, normally UTC) -## Example: 'Australia/Sydney' -# timezone: - -# Deployment Annotations -deploymentAnnotations: {} - -# To be added to the database server pod(s) -podAnnotations: {} -podLabels: {} - -## Set pod priorityClassName -# priorityClassName: {} - - -## Init container resources defaults -initContainer: - resources: - requests: - memory: 10Mi - cpu: 10m diff --git a/deployment/deployment/middleware_deployment/zookeeper/Chart.yaml b/deployment/deployment/middleware_deployment/zookeeper/Chart.yaml deleted file mode 100644 index b65d835..0000000 --- a/deployment/deployment/middleware_deployment/zookeeper/Chart.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -name: zookeeper -home: https://zookeeper.apache.org/ -version: 2.1.6 -appVersion: 3.5.5 -kubeVersion: "^1.10.0-0" -description: DEPRECATED Centralized service for maintaining configuration information, naming, - providing distributed synchronization, and providing group services. -icon: https://zookeeper.apache.org/images/zookeeper_small.gif -sources: -- https://github.com/apache/zookeeper -- https://github.com/kubernetes/contrib/tree/master/statefulsets/zookeeper -deprecated: true diff --git a/deployment/deployment/middleware_deployment/zookeeper/README.md b/deployment/deployment/middleware_deployment/zookeeper/README.md deleted file mode 100644 index f05dcd2..0000000 --- a/deployment/deployment/middleware_deployment/zookeeper/README.md +++ /dev/null @@ -1,154 +0,0 @@ -# ⚠️ Repo Archive Notice - -As of Nov 13, 2020, charts in this repo will no longer be updated. -For more information, see the Helm Charts [Deprecation and Archive Notice](https://github.com/helm/charts#%EF%B8%8F-deprecation-and-archive-notice), and [Update](https://helm.sh/blog/charts-repo-deprecation/). - -# incubator/zookeeper - -This helm chart provides an implementation of the ZooKeeper [StatefulSet](http://kubernetes.io/docs/concepts/abstractions/controllers/statefulsets/) found in Kubernetes Contrib [Zookeeper StatefulSet](https://github.com/kubernetes/contrib/tree/master/statefulsets/zookeeper). - -## DEPRECATION NOTICE - -This chart is deprecated and no longer supported. - -## Prerequisites -* Kubernetes 1.10+ -* PersistentVolume support on the underlying infrastructure -* A dynamic provisioner for the PersistentVolumes -* A familiarity with [Apache ZooKeeper 3.5.x](https://zookeeper.apache.org/doc/r3.5.5/) - -## Chart Components -This chart will do the following: - -* Create a fixed size ZooKeeper ensemble using a [StatefulSet](http://kubernetes.io/docs/concepts/abstractions/controllers/statefulsets/). -* Create a [PodDisruptionBudget](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-disruption-budget/) so kubectl drain will respect the Quorum size of the ensemble. -* Create a [Headless Service](https://kubernetes.io/docs/concepts/services-networking/service/) to control the domain of the ZooKeeper ensemble. -* Create a Service configured to connect to the available ZooKeeper instance on the configured client port. -* Optionally apply a [Pod Anti-Affinity](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#inter-pod-affinity-and-anti-affinity-beta-feature) to spread the ZooKeeper ensemble across nodes. -* Optionally start JMX Exporter and Zookeeper Exporter containers inside Zookeeper pods. -* Optionally create a job which creates Zookeeper chroots (e.g. `/kafka1`). -* Optionally create a Prometheus ServiceMonitor for each enabled exporter container - -## Installing the Chart -You can install the chart with the release name `zookeeper` as below. - -```console -$ helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator -$ helm install --name zookeeper incubator/zookeeper -``` - -If you do not specify a name, helm will select a name for you. - -### Installed Components -You can use `kubectl get` to view all of the installed components. - -```console{%raw} -$ kubectl get all -l app=zookeeper -NAME: zookeeper -LAST DEPLOYED: Wed Apr 11 17:09:48 2018 -NAMESPACE: default -STATUS: DEPLOYED - -RESOURCES: -==> v1beta1/PodDisruptionBudget -NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE -zookeeper N/A 1 1 2m - -==> v1/Service -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -zookeeper-headless ClusterIP None 2181/TCP,3888/TCP,2888/TCP 2m -zookeeper ClusterIP 10.98.179.165 2181/TCP 2m - -==> v1beta1/StatefulSet -NAME DESIRED CURRENT AGE -zookeeper 3 3 2m - -==> monitoring.coreos.com/v1/ServiceMonitor -NAME AGE -zookeeper 2m -zookeeper-exporter 2m -``` - -1. `statefulsets/zookeeper` is the StatefulSet created by the chart. -1. `po/zookeeper-<0|1|2>` are the Pods created by the StatefulSet. Each Pod has a single container running a ZooKeeper server. -1. `svc/zookeeper-headless` is the Headless Service used to control the network domain of the ZooKeeper ensemble. -1. `svc/zookeeper` is a Service that can be used by clients to connect to an available ZooKeeper server. -1. `servicemonitor/zookeeper` is a Prometheus ServiceMonitor which scrapes the jmx-exporter metrics endpoint -1. `servicemonitor/zookeeper-exporter` is a Prometheus ServiceMonitor which scrapes the zookeeper-exporter metrics endpoint - -## Configuration -You can specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. - -Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, - -```console -$ helm install --name my-release -f values.yaml incubator/zookeeper -``` - -## Default Values - -- You can find all user-configurable settings, their defaults and commentary about them in [values.yaml](values.yaml). - -## Deep Dive - -## Image Details -The image used for this chart is based on Alpine 3.9.0. - -## JVM Details -The Java Virtual Machine used for this chart is the OpenJDK JVM 8u192 JRE (headless). - -## ZooKeeper Details -The chart defaults to ZooKeeper 3.5 (latest released version). - -## Failover -You can test failover by killing the leader. Insert a key: -```console -$ kubectl exec zookeeper-0 -- bin/zkCli.sh create /foo bar; -$ kubectl exec zookeeper-2 -- bin/zkCli.sh get /foo; -``` - -Watch existing members: -```console -$ kubectl run --attach bbox --image=busybox --restart=Never -- sh -c 'while true; do for i in 0 1 2; do echo zk-${i} $(echo stats | nc -${i}.:2181 | grep Mode); sleep 1; done; done'; - -zk-2 Mode: follower -zk-0 Mode: follower -zk-1 Mode: leader -zk-2 Mode: follower -``` - -Delete Pods and wait for the StatefulSet controller to bring them back up: -```console -$ kubectl delete po -l app=zookeeper -$ kubectl get po --watch-only -NAME READY STATUS RESTARTS AGE -zookeeper-0 0/1 Running 0 35s -zookeeper-0 1/1 Running 0 50s -zookeeper-1 0/1 Pending 0 0s -zookeeper-1 0/1 Pending 0 0s -zookeeper-1 0/1 ContainerCreating 0 0s -zookeeper-1 0/1 Running 0 19s -zookeeper-1 1/1 Running 0 40s -zookeeper-2 0/1 Pending 0 0s -zookeeper-2 0/1 Pending 0 0s -zookeeper-2 0/1 ContainerCreating 0 0s -zookeeper-2 0/1 Running 0 19s -zookeeper-2 1/1 Running 0 41s -``` - -Check the previously inserted key: -```console -$ kubectl exec zookeeper-1 -- bin/zkCli.sh get /foo -ionid = 0x354887858e80035, negotiated timeout = 30000 - -WATCHER:: - -WatchedEvent state:SyncConnected type:None path:null -bar -``` - -## Scaling -ZooKeeper can not be safely scaled in versions prior to 3.5.x - -## Limitations -* Only supports storage options that have backends for persistent volume claims. diff --git a/deployment/deployment/middleware_deployment/zookeeper/templates/NOTES.txt b/deployment/deployment/middleware_deployment/zookeeper/templates/NOTES.txt deleted file mode 100644 index 6c5da85..0000000 --- a/deployment/deployment/middleware_deployment/zookeeper/templates/NOTES.txt +++ /dev/null @@ -1,7 +0,0 @@ -Thank you for installing ZooKeeper on your Kubernetes cluster. More information -about ZooKeeper can be found at https://zookeeper.apache.org/doc/current/ - -Your connection string should look like: - {{ template "zookeeper.fullname" . }}-0.{{ template "zookeeper.fullname" . }}-headless:{{ .Values.service.ports.client.port }},{{ template "zookeeper.fullname" . }}-1.{{ template "zookeeper.fullname" . }}-headless:{{ .Values.service.ports.client.port }},... - -You can also use the client service {{ template "zookeeper.fullname" . }}:{{ .Values.service.ports.client.port }} to connect to an available ZooKeeper server. diff --git a/deployment/deployment/middleware_deployment/zookeeper/templates/_helpers.tpl b/deployment/deployment/middleware_deployment/zookeeper/templates/_helpers.tpl deleted file mode 100644 index 0e15107..0000000 --- a/deployment/deployment/middleware_deployment/zookeeper/templates/_helpers.tpl +++ /dev/null @@ -1,46 +0,0 @@ -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "zookeeper.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 "zookeeper.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "zookeeper.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -The name of the zookeeper headless service. -*/}} -{{- define "zookeeper.headless" -}} -{{- printf "%s-headless" (include "zookeeper.fullname" .) | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -The name of the zookeeper chroots job. -*/}} -{{- define "zookeeper.chroots" -}} -{{- printf "%s-chroots" (include "zookeeper.fullname" .) | trunc 63 | trimSuffix "-" -}} -{{- end -}} diff --git a/deployment/deployment/middleware_deployment/zookeeper/templates/config-jmx-exporter.yaml b/deployment/deployment/middleware_deployment/zookeeper/templates/config-jmx-exporter.yaml deleted file mode 100644 index 79905e5..0000000 --- a/deployment/deployment/middleware_deployment/zookeeper/templates/config-jmx-exporter.yaml +++ /dev/null @@ -1,19 +0,0 @@ -{{- if .Values.exporters.jmx.enabled }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ .Release.Name }}-jmx-exporter - labels: - app: {{ template "zookeeper.name" . }} - chart: {{ template "zookeeper.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -data: - config.yml: |- - hostPort: 127.0.0.1:{{ .Values.env.JMXPORT }} - lowercaseOutputName: {{ .Values.exporters.jmx.config.lowercaseOutputName }} - rules: -{{ .Values.exporters.jmx.config.rules | toYaml | indent 6 }} - ssl: false - startDelaySeconds: {{ .Values.exporters.jmx.config.startDelaySeconds }} -{{- end }} diff --git a/deployment/deployment/middleware_deployment/zookeeper/templates/config-script.yaml b/deployment/deployment/middleware_deployment/zookeeper/templates/config-script.yaml deleted file mode 100644 index 2b4b44d..0000000 --- a/deployment/deployment/middleware_deployment/zookeeper/templates/config-script.yaml +++ /dev/null @@ -1,110 +0,0 @@ ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "zookeeper.fullname" . }} - labels: - app: {{ template "zookeeper.name" . }} - chart: {{ template "zookeeper.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} - component: server -data: - ok: | - #!/bin/sh - zkServer.sh status - - ready: | - #!/bin/sh - echo ruok | nc 127.0.0.1 ${1:-2181} - - run: | - #!/bin/bash - - set -a - ROOT=$(echo /apache-zookeeper-*) - - ZK_USER=${ZK_USER:-"zookeeper"} - ZK_LOG_LEVEL=${ZK_LOG_LEVEL:-"INFO"} - ZK_DATA_DIR=${ZK_DATA_DIR:-"/data"} - ZK_DATA_LOG_DIR=${ZK_DATA_LOG_DIR:-"/data/log"} - ZK_CONF_DIR=${ZK_CONF_DIR:-"/conf"} - ZK_CLIENT_PORT=${ZK_CLIENT_PORT:-2181} - ZK_SERVER_PORT=${ZK_SERVER_PORT:-2888} - ZK_ELECTION_PORT=${ZK_ELECTION_PORT:-3888} - ZK_TICK_TIME=${ZK_TICK_TIME:-2000} - ZK_INIT_LIMIT=${ZK_INIT_LIMIT:-10} - ZK_SYNC_LIMIT=${ZK_SYNC_LIMIT:-5} - ZK_HEAP_SIZE=${ZK_HEAP_SIZE:-2G} - ZK_MAX_CLIENT_CNXNS=${ZK_MAX_CLIENT_CNXNS:-60} - ZK_MIN_SESSION_TIMEOUT=${ZK_MIN_SESSION_TIMEOUT:- $((ZK_TICK_TIME*2))} - ZK_MAX_SESSION_TIMEOUT=${ZK_MAX_SESSION_TIMEOUT:- $((ZK_TICK_TIME*20))} - ZK_SNAP_RETAIN_COUNT=${ZK_SNAP_RETAIN_COUNT:-3} - ZK_PURGE_INTERVAL=${ZK_PURGE_INTERVAL:-0} - ID_FILE="$ZK_DATA_DIR/myid" - ZK_CONFIG_FILE="$ZK_CONF_DIR/zoo.cfg" - LOG4J_PROPERTIES="$ZK_CONF_DIR/log4j.properties" - HOST=$(hostname) - DOMAIN=`hostname -d` - JVMFLAGS="-Xmx$ZK_HEAP_SIZE -Xms$ZK_HEAP_SIZE" - - APPJAR=$(echo $ROOT/*jar) - CLASSPATH="${ROOT}/lib/*:${APPJAR}:${ZK_CONF_DIR}:" - - if [[ $HOST =~ (.*)-([0-9]+)$ ]]; then - NAME=${BASH_REMATCH[1]} - ORD=${BASH_REMATCH[2]} - MY_ID=$((ORD+1)) - else - echo "Failed to extract ordinal from hostname $HOST" - exit 1 - fi - - mkdir -p $ZK_DATA_DIR - mkdir -p $ZK_DATA_LOG_DIR - echo $MY_ID >> $ID_FILE - - echo "clientPort=$ZK_CLIENT_PORT" >> $ZK_CONFIG_FILE - echo "dataDir=$ZK_DATA_DIR" >> $ZK_CONFIG_FILE - echo "dataLogDir=$ZK_DATA_LOG_DIR" >> $ZK_CONFIG_FILE - echo "tickTime=$ZK_TICK_TIME" >> $ZK_CONFIG_FILE - echo "initLimit=$ZK_INIT_LIMIT" >> $ZK_CONFIG_FILE - echo "syncLimit=$ZK_SYNC_LIMIT" >> $ZK_CONFIG_FILE - echo "maxClientCnxns=$ZK_MAX_CLIENT_CNXNS" >> $ZK_CONFIG_FILE - echo "minSessionTimeout=$ZK_MIN_SESSION_TIMEOUT" >> $ZK_CONFIG_FILE - echo "maxSessionTimeout=$ZK_MAX_SESSION_TIMEOUT" >> $ZK_CONFIG_FILE - echo "autopurge.snapRetainCount=$ZK_SNAP_RETAIN_COUNT" >> $ZK_CONFIG_FILE - echo "autopurge.purgeInterval=$ZK_PURGE_INTERVAL" >> $ZK_CONFIG_FILE - echo "4lw.commands.whitelist=*" >> $ZK_CONFIG_FILE - - for (( i=1; i<=$ZK_REPLICAS; i++ )) - do - echo "server.$i=$NAME-$((i-1)).$DOMAIN:$ZK_SERVER_PORT:$ZK_ELECTION_PORT" >> $ZK_CONFIG_FILE - done - - rm -f $LOG4J_PROPERTIES - - echo "zookeeper.root.logger=$ZK_LOG_LEVEL, CONSOLE" >> $LOG4J_PROPERTIES - echo "zookeeper.console.threshold=$ZK_LOG_LEVEL" >> $LOG4J_PROPERTIES - echo "zookeeper.log.threshold=$ZK_LOG_LEVEL" >> $LOG4J_PROPERTIES - echo "zookeeper.log.dir=$ZK_DATA_LOG_DIR" >> $LOG4J_PROPERTIES - echo "zookeeper.log.file=zookeeper.log" >> $LOG4J_PROPERTIES - echo "zookeeper.log.maxfilesize=256MB" >> $LOG4J_PROPERTIES - echo "zookeeper.log.maxbackupindex=10" >> $LOG4J_PROPERTIES - echo "zookeeper.tracelog.dir=$ZK_DATA_LOG_DIR" >> $LOG4J_PROPERTIES - echo "zookeeper.tracelog.file=zookeeper_trace.log" >> $LOG4J_PROPERTIES - echo "log4j.rootLogger=\${zookeeper.root.logger}" >> $LOG4J_PROPERTIES - echo "log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender" >> $LOG4J_PROPERTIES - echo "log4j.appender.CONSOLE.Threshold=\${zookeeper.console.threshold}" >> $LOG4J_PROPERTIES - echo "log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout" >> $LOG4J_PROPERTIES - echo "log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n" >> $LOG4J_PROPERTIES - - if [ -n "$JMXDISABLE" ] - then - MAIN=org.apache.zookeeper.server.quorum.QuorumPeerMain - else - MAIN="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=$JMXPORT -Dcom.sun.management.jmxremote.authenticate=$JMXAUTH -Dcom.sun.management.jmxremote.ssl=$JMXSSL -Dzookeeper.jmx.log4j.disable=$JMXLOG4J org.apache.zookeeper.server.quorum.QuorumPeerMain" - fi - - set -x - exec java -cp "$CLASSPATH" $JVMFLAGS $MAIN $ZK_CONFIG_FILE diff --git a/deployment/deployment/middleware_deployment/zookeeper/templates/job-chroots.yaml b/deployment/deployment/middleware_deployment/zookeeper/templates/job-chroots.yaml deleted file mode 100644 index 3aa08c9..0000000 --- a/deployment/deployment/middleware_deployment/zookeeper/templates/job-chroots.yaml +++ /dev/null @@ -1,65 +0,0 @@ -{{- if .Values.jobs.chroots.enabled }} -{{- $root := . }} -{{- $job := .Values.jobs.chroots }} -apiVersion: batch/v1 -kind: Job -metadata: - name: {{ template "zookeeper.chroots" . }} - annotations: - "helm.sh/hook": post-install,post-upgrade - "helm.sh/hook-weight": "-5" - "helm.sh/hook-delete-policy": hook-succeeded - labels: - app: {{ template "zookeeper.name" . }} - chart: {{ template "zookeeper.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} - component: jobs - job: chroots -spec: - activeDeadlineSeconds: {{ $job.activeDeadlineSeconds }} - backoffLimit: {{ $job.backoffLimit }} - completions: {{ $job.completions }} - parallelism: {{ $job.parallelism }} - template: - metadata: - labels: - app: {{ template "zookeeper.name" . }} - release: {{ .Release.Name }} - component: jobs - job: chroots - spec: - restartPolicy: {{ $job.restartPolicy }} -{{- if .Values.priorityClassName }} - priorityClassName: "{{ .Values.priorityClassName }}" -{{- end }} - containers: - - name: main - image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - command: - - /bin/bash - - -o - - pipefail - - -euc - {{- $port := .Values.service.ports.client.port }} - - > - sleep 15; - export SERVER={{ template "zookeeper.fullname" $root }}:{{ $port }}; - {{- range $job.config.create }} - echo '==> {{ . }}'; - echo '====> Create chroot if does not exist.'; - zkCli.sh -server {{ template "zookeeper.fullname" $root }}:{{ $port }} get {{ . }} 2>&1 >/dev/null | grep 'cZxid' - || zkCli.sh -server {{ template "zookeeper.fullname" $root }}:{{ $port }} create {{ . }} ""; - echo '====> Confirm chroot exists.'; - zkCli.sh -server {{ template "zookeeper.fullname" $root }}:{{ $port }} get {{ . }} 2>&1 >/dev/null | grep 'cZxid'; - echo '====> Chroot exists.'; - {{- end }} - env: - {{- range $key, $value := $job.env }} - - name: {{ $key | upper | replace "." "_" }} - value: {{ $value | quote }} - {{- end }} - resources: -{{ toYaml $job.resources | indent 12 }} -{{- end -}} diff --git a/deployment/deployment/middleware_deployment/zookeeper/templates/poddisruptionbudget.yaml b/deployment/deployment/middleware_deployment/zookeeper/templates/poddisruptionbudget.yaml deleted file mode 100644 index 15ee008..0000000 --- a/deployment/deployment/middleware_deployment/zookeeper/templates/poddisruptionbudget.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: policy/v1beta1 -kind: PodDisruptionBudget -metadata: - name: {{ template "zookeeper.fullname" . }} - labels: - app: {{ template "zookeeper.name" . }} - chart: {{ template "zookeeper.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} - component: server -spec: - selector: - matchLabels: - app: {{ template "zookeeper.name" . }} - release: {{ .Release.Name }} - component: server -{{ toYaml .Values.podDisruptionBudget | indent 2 }} diff --git a/deployment/deployment/middleware_deployment/zookeeper/templates/service-headless.yaml b/deployment/deployment/middleware_deployment/zookeeper/templates/service-headless.yaml deleted file mode 100644 index 3193a1b..0000000 --- a/deployment/deployment/middleware_deployment/zookeeper/templates/service-headless.yaml +++ /dev/null @@ -1,28 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ template "zookeeper.headless" . }} - labels: - app: {{ template "zookeeper.name" . }} - chart: {{ template "zookeeper.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -{{- if .Values.headless.annotations }} - annotations: -{{ .Values.headless.annotations | toYaml | trimSuffix "\n" | indent 4 }} -{{- end }} -spec: - clusterIP: None -{{- if .Values.headless.publishNotReadyAddresses }} - publishNotReadyAddresses: true -{{- end }} - ports: -{{- range $key, $port := .Values.ports }} - - name: {{ $key }} - port: {{ $port.containerPort }} - targetPort: {{ $key }} - protocol: {{ $port.protocol }} -{{- end }} - selector: - app: {{ template "zookeeper.name" . }} - release: {{ .Release.Name }} diff --git a/deployment/deployment/middleware_deployment/zookeeper/templates/service.yaml b/deployment/deployment/middleware_deployment/zookeeper/templates/service.yaml deleted file mode 100644 index 09fc1dc..0000000 --- a/deployment/deployment/middleware_deployment/zookeeper/templates/service.yaml +++ /dev/null @@ -1,41 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ template "zookeeper.fullname" . }} - labels: - app: {{ template "zookeeper.name" . }} - chart: {{ template "zookeeper.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -{{- if .Values.service.annotations }} - annotations: -{{- with .Values.service.annotations }} -{{ toYaml . | indent 4 }} -{{- end }} -{{- end }} -spec: - type: {{ .Values.service.type }} - ports: - {{- range $key, $value := .Values.service.ports }} - - name: {{ $key }} -{{ toYaml $value | indent 6 }} - {{- end }} -{{- if .Values.exporters.jmx.enabled }} - {{- range $key, $port := .Values.exporters.jmx.ports }} - - name: {{ $key }} - port: {{ $port.containerPort }} - targetPort: {{ $key }} - protocol: {{ $port.protocol }} - {{- end }} -{{- end}} -{{- if .Values.exporters.zookeeper.enabled }} - {{- range $key, $port := .Values.exporters.zookeeper.ports }} - - name: {{ $key }} - port: {{ $port.containerPort }} - targetPort: {{ $key }} - protocol: {{ $port.protocol }} - {{- end }} -{{- end}} - selector: - app: {{ template "zookeeper.name" . }} - release: {{ .Release.Name }} diff --git a/deployment/deployment/middleware_deployment/zookeeper/templates/servicemonitors.yaml b/deployment/deployment/middleware_deployment/zookeeper/templates/servicemonitors.yaml deleted file mode 100644 index 0a230a2..0000000 --- a/deployment/deployment/middleware_deployment/zookeeper/templates/servicemonitors.yaml +++ /dev/null @@ -1,56 +0,0 @@ -{{- if and .Values.exporters.jmx.enabled .Values.prometheus.serviceMonitor.enabled }} -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: {{ include "zookeeper.fullname" . }} - {{- if .Values.prometheus.serviceMonitor.namespace }} - namespace: {{ .Values.prometheus.serviceMonitor.namespace }} - {{- end }} - labels: -{{ toYaml .Values.prometheus.serviceMonitor.selector | indent 4 }} -spec: - endpoints: - {{- range $key, $port := .Values.exporters.jmx.ports }} - - port: {{ $key }} - path: {{ $.Values.exporters.jmx.path }} - interval: {{ $.Values.exporters.jmx.serviceMonitor.interval }} - scrapeTimeout: {{ $.Values.exporters.jmx.serviceMonitor.scrapeTimeout }} - scheme: {{ $.Values.exporters.jmx.serviceMonitor.scheme }} - {{- end }} - selector: - matchLabels: - app: {{ include "zookeeper.name" . }} - release: {{ .Release.Name }} - namespaceSelector: - matchNames: - - {{ .Release.Namespace }} -{{- end }} ---- - -{{- if and .Values.exporters.zookeeper.enabled .Values.prometheus.serviceMonitor.enabled }} -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: {{ include "zookeeper.fullname" . }}-exporter - {{- if .Values.prometheus.serviceMonitor.namespace }} - namespace: {{ .Values.prometheus.serviceMonitor.namespace }} - {{- end }} - labels: -{{ toYaml .Values.prometheus.serviceMonitor.selector | indent 4 }} -spec: - endpoints: - {{- range $key, $port := .Values.exporters.zookeeper.ports }} - - port: {{ $key }} - path: {{ $.Values.exporters.zookeeper.path }} - interval: {{ $.Values.exporters.zookeeper.serviceMonitor.interval }} - scrapeTimeout: {{ $.Values.exporters.zookeeper.serviceMonitor.scrapeTimeout }} - scheme: {{ $.Values.exporters.zookeeper.serviceMonitor.scheme }} - {{- end }} - selector: - matchLabels: - app: {{ include "zookeeper.name" . }} - release: {{ .Release.Name }} - namespaceSelector: - matchNames: - - {{ .Release.Namespace }} -{{- end }} \ No newline at end of file diff --git a/deployment/deployment/middleware_deployment/zookeeper/templates/statefulset.yaml b/deployment/deployment/middleware_deployment/zookeeper/templates/statefulset.yaml deleted file mode 100644 index 6d508a6..0000000 --- a/deployment/deployment/middleware_deployment/zookeeper/templates/statefulset.yaml +++ /dev/null @@ -1,226 +0,0 @@ -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: {{ template "zookeeper.fullname" . }} - labels: - app: {{ template "zookeeper.name" . }} - chart: {{ template "zookeeper.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} - component: server -spec: - serviceName: {{ template "zookeeper.headless" . }} - replicas: {{ .Values.replicaCount }} - selector: - matchLabels: - app: {{ template "zookeeper.name" . }} - release: {{ .Release.Name }} - component: server - updateStrategy: -{{ toYaml .Values.updateStrategy | indent 4 }} - template: - metadata: - labels: - app: {{ template "zookeeper.name" . }} - release: {{ .Release.Name }} - component: server - {{- if .Values.podLabels }} - ## Custom pod labels - {{- range $key, $value := .Values.podLabels }} - {{ $key }}: {{ $value | quote }} - {{- end }} - {{- end }} -{{- if .Values.podAnnotations }} - annotations: - ## Custom pod annotations - {{- range $key, $value := .Values.podAnnotations }} - {{ $key }}: {{ $value | quote }} - {{- end }} -{{- end }} - spec: - terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} -{{- if .Values.schedulerName }} - schedulerName: "{{ .Values.schedulerName }}" -{{- end }} - securityContext: -{{ toYaml .Values.securityContext | indent 8 }} -{{- if .Values.priorityClassName }} - priorityClassName: "{{ .Values.priorityClassName }}" -{{- end }} - containers: - - - name: zookeeper - image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - {{- with .Values.command }} - command: {{ range . }} - - {{ . | quote }} - {{- end }} - {{- end }} - ports: -{{- range $key, $port := .Values.ports }} - - name: {{ $key }} -{{ toYaml $port | indent 14 }} -{{- end }} - livenessProbe: - exec: - command: - - sh - - /config-scripts/ok - initialDelaySeconds: 20 - periodSeconds: 30 - timeoutSeconds: 5 - failureThreshold: 2 - successThreshold: 1 - readinessProbe: - exec: - command: - - sh - - /config-scripts/ready - initialDelaySeconds: 20 - periodSeconds: 30 - timeoutSeconds: 5 - failureThreshold: 2 - successThreshold: 1 - env: - - name: ZK_REPLICAS - value: {{ .Values.replicaCount | quote }} - {{- range $key, $value := .Values.env }} - - name: {{ $key | upper | replace "." "_" }} - value: {{ $value | quote }} - {{- end }} - {{- range $secret := .Values.secrets }} - {{- range $key := $secret.keys }} - - name: {{ (print $secret.name "_" $key) | upper }} - valueFrom: - secretKeyRef: - name: {{ $secret.name }} - key: {{ $key }} - {{- end }} - {{- end }} - resources: -{{ toYaml .Values.resources | indent 12 }} - volumeMounts: - - name: data - mountPath: /data - {{- range $secret := .Values.secrets }} - {{- if $secret.mountPath }} - {{- range $key := $secret.keys }} - - name: {{ $.Release.Name }}-{{ $secret.name }} - mountPath: {{ $secret.mountPath }}/{{ $key }} - subPath: {{ $key }} - readOnly: true - {{- end }} - {{- end }} - {{- end }} - - name: config - mountPath: /config-scripts - - -{{- if .Values.exporters.jmx.enabled }} - - name: jmx-exporter - image: "{{ .Values.exporters.jmx.image.repository }}:{{ .Values.exporters.jmx.image.tag }}" - imagePullPolicy: {{ .Values.exporters.jmx.image.pullPolicy }} - ports: - {{- range $key, $port := .Values.exporters.jmx.ports }} - - name: {{ $key }} -{{ toYaml $port | indent 14 }} - {{- end }} - livenessProbe: -{{ toYaml .Values.exporters.jmx.livenessProbe | indent 12 }} - readinessProbe: -{{ toYaml .Values.exporters.jmx.readinessProbe | indent 12 }} - env: - - name: SERVICE_PORT - value: {{ .Values.exporters.jmx.ports.jmxxp.containerPort | quote }} - {{- with .Values.exporters.jmx.env }} - {{- range $key, $value := . }} - - name: {{ $key | upper | replace "." "_" }} - value: {{ $value | quote }} - {{- end }} - {{- end }} - resources: -{{ toYaml .Values.exporters.jmx.resources | indent 12 }} - volumeMounts: - - name: config-jmx-exporter - mountPath: /opt/jmx_exporter/config.yml - subPath: config.yml -{{- end }} - -{{- if .Values.exporters.zookeeper.enabled }} - - name: zookeeper-exporter - image: "{{ .Values.exporters.zookeeper.image.repository }}:{{ .Values.exporters.zookeeper.image.tag }}" - imagePullPolicy: {{ .Values.exporters.zookeeper.image.pullPolicy }} - args: - - -bind-addr=:{{ .Values.exporters.zookeeper.ports.zookeeperxp.containerPort }} - - -metrics-path={{ .Values.exporters.zookeeper.path }} - - -zookeeper=localhost:{{ .Values.ports.client.containerPort }} - - -log-level={{ .Values.exporters.zookeeper.config.logLevel }} - - -reset-on-scrape={{ .Values.exporters.zookeeper.config.resetOnScrape }} - ports: - {{- range $key, $port := .Values.exporters.zookeeper.ports }} - - name: {{ $key }} -{{ toYaml $port | indent 14 }} - {{- end }} - livenessProbe: -{{ toYaml .Values.exporters.zookeeper.livenessProbe | indent 12 }} - readinessProbe: -{{ toYaml .Values.exporters.zookeeper.readinessProbe | indent 12 }} - env: - {{- range $key, $value := .Values.exporters.zookeeper.env }} - - name: {{ $key | upper | replace "." "_" }} - value: {{ $value | quote }} - {{- end }} - resources: -{{ toYaml .Values.exporters.zookeeper.resources | indent 12 }} -{{- end }} - - {{- with .Values.nodeSelector }} - nodeSelector: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: -{{ toYaml . | indent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: -{{ toYaml . | indent 8 }} - {{- end }} - volumes: - - name: config - configMap: - name: {{ template "zookeeper.fullname" . }} - defaultMode: 0555 - {{- range .Values.secrets }} - - name: {{ $.Release.Name }}-{{ .name }} - secret: - secretName: {{ .name }} - {{- end }} - {{- if .Values.exporters.jmx.enabled }} - - name: config-jmx-exporter - configMap: - name: {{ .Release.Name }}-jmx-exporter - {{- end }} - {{- if not .Values.persistence.enabled }} - - name: data - emptyDir: {} - {{- end }} - {{- if .Values.persistence.enabled }} - volumeClaimTemplates: - - metadata: - name: data - spec: - accessModes: - - {{ .Values.persistence.accessMode | quote }} - resources: - requests: - storage: {{ .Values.persistence.size | quote }} - {{- if .Values.persistence.storageClass }} - {{- if (eq "-" .Values.persistence.storageClass) }} - storageClassName: "" - {{- else }} - storageClassName: "{{ .Values.persistence.storageClass }}" - {{- end }} - {{- end }} - {{- end }} diff --git a/deployment/deployment/middleware_deployment/zookeeper/values.yaml b/deployment/deployment/middleware_deployment/zookeeper/values.yaml deleted file mode 100644 index df70b11..0000000 --- a/deployment/deployment/middleware_deployment/zookeeper/values.yaml +++ /dev/null @@ -1,300 +0,0 @@ -## As weighted quorums are not supported, it is imperative that an odd number of replicas -## be chosen. Moreover, the number of replicas should be either 1, 3, 5, or 7. -## -## ref: https://github.com/kubernetes/contrib/tree/master/statefulsets/zookeeper#stateful-set -replicaCount: 1 # Desired quantity of ZooKeeper pods. This should always be (1,3,5, or 7) - -podDisruptionBudget: - maxUnavailable: 1 # Limits how many Zokeeper pods may be unavailable due to voluntary disruptions. - -terminationGracePeriodSeconds: 1800 # Duration in seconds a Zokeeper pod needs to terminate gracefully. - -updateStrategy: - type: RollingUpdate - -## refs: -## - https://github.com/kubernetes/contrib/tree/master/statefulsets/zookeeper -## - https://github.com/kubernetes/contrib/blob/master/statefulsets/zookeeper/Makefile#L1 -image: - repository: zookeeper # Container image repository for zookeeper container. - tag: 3.5.5 # Container image tag for zookeeper container. - pullPolicy: IfNotPresent # Image pull criteria for zookeeper container. - -service: - type: ClusterIP # Exposes zookeeper on a cluster-internal IP. - annotations: {} # Arbitrary non-identifying metadata for zookeeper service. - ## AWS example for use with LoadBalancer service type. - # external-dns.alpha.kubernetes.io/hostname: zookeeper.cluster.local - # service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true" - # service.beta.kubernetes.io/aws-load-balancer-internal: "true" - ports: - client: - port: 2181 # Service port number for client port. - targetPort: client # Service target port for client port. - protocol: TCP # Service port protocol for client port. - -## Headless service. -## -headless: - annotations: {} - # publishNotReadyAddresses, default false for backward compatibility - # set to true to register DNS entries for unready pods, which helps in rare - # occasions when cluster is unable to be created, DNS caching is enforced - # or pods are in persistent crash loop - publishNotReadyAddresses: false - -ports: - client: - containerPort: 2181 # Port number for zookeeper container client port. - protocol: TCP # Protocol for zookeeper container client port. - election: - containerPort: 3888 # Port number for zookeeper container election port. - protocol: TCP # Protocol for zookeeper container election port. - server: - containerPort: 2888 # Port number for zookeeper container server port. - protocol: TCP # Protocol for zookeeper container server port. - -resources: {} # Optionally specify how much CPU and memory (RAM) each zookeeper container needs. - # 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:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi - -priorityClassName: "" - -nodeSelector: {} # Node label-values required to run zookeeper pods. - -tolerations: [] # Node taint overrides for zookeeper pods. - -affinity: {} # Criteria by which pod label-values influence scheduling for zookeeper pods. - # podAntiAffinity: - # requiredDuringSchedulingIgnoredDuringExecution: - # - topologyKey: "kubernetes.io/hostname" - # labelSelector: - # matchLabels: - # release: zookeeper - -podAnnotations: {} # Arbitrary non-identifying metadata for zookeeper pods. - # prometheus.io/scrape: "true" - # prometheus.io/path: "/metrics" - # prometheus.io/port: "9141" - -podLabels: {} # Key/value pairs that are attached to zookeeper pods. - # team: "developers" - # service: "zookeeper" - -securityContext: - fsGroup: 1000 - runAsUser: 1000 - -## Useful, if you want to use an alternate image. -command: - - /bin/bash - - -xec - - /config-scripts/run - -## Useful if using any custom authorizer. -## Pass any secrets to the kafka pods. Each secret will be passed as an -## environment variable by default. The secret can also be mounted to a -## specific path (in addition to environment variable) if required. Environment -## variable names are generated as: `_` (All upper case) -# secrets: -# - name: myKafkaSecret -# keys: -# - username -# - password -# # mountPath: /opt/kafka/secret -# - name: myZkSecret -# keys: -# - user -# - pass -# mountPath: /opt/zookeeper/secret - -persistence: - enabled: false - ## zookeeper data 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: "csi-high-perf" - accessMode: ReadWriteOnce - size: 5Gi - -## Exporters query apps for metrics and make those metrics available for -## Prometheus to scrape. -exporters: - - jmx: - enabled: false - image: - repository: sscaling/jmx-prometheus-exporter - tag: 0.3.0 - pullPolicy: IfNotPresent - config: - lowercaseOutputName: false - ## ref: https://github.com/prometheus/jmx_exporter/blob/master/example_configs/zookeeper.yaml - rules: - - pattern: "org.apache.ZooKeeperService<>(\\w+)" - name: "zookeeper_$2" - - pattern: "org.apache.ZooKeeperService<>(\\w+)" - name: "zookeeper_$3" - labels: - replicaId: "$2" - - pattern: "org.apache.ZooKeeperService<>(\\w+)" - name: "zookeeper_$4" - labels: - replicaId: "$2" - memberType: "$3" - - pattern: "org.apache.ZooKeeperService<>(\\w+)" - name: "zookeeper_$4_$5" - labels: - replicaId: "$2" - memberType: "$3" - startDelaySeconds: 30 - env: {} - resources: {} - path: /metrics - ports: - jmxxp: - containerPort: 9404 - protocol: TCP - livenessProbe: - httpGet: - path: /metrics - port: jmxxp - initialDelaySeconds: 30 - periodSeconds: 15 - timeoutSeconds: 60 - failureThreshold: 8 - successThreshold: 1 - readinessProbe: - httpGet: - path: /metrics - port: jmxxp - initialDelaySeconds: 30 - periodSeconds: 15 - timeoutSeconds: 60 - failureThreshold: 8 - successThreshold: 1 - serviceMonitor: - interval: 30s - scrapeTimeout: 30s - scheme: http - - zookeeper: - ## refs: - ## - https://github.com/carlpett/zookeeper_exporter - ## - https://hub.docker.com/r/josdotso/zookeeper-exporter/ - ## - https://www.datadoghq.com/blog/monitoring-kafka-performance-metrics/#zookeeper-metrics - enabled: false - image: - repository: josdotso/zookeeper-exporter - tag: v1.1.2 - pullPolicy: IfNotPresent - config: - logLevel: info - resetOnScrape: "true" - env: {} - resources: {} - path: /metrics - ports: - zookeeperxp: - containerPort: 9141 - protocol: TCP - livenessProbe: - httpGet: - path: /metrics - port: zookeeperxp - initialDelaySeconds: 30 - periodSeconds: 15 - timeoutSeconds: 60 - failureThreshold: 8 - successThreshold: 1 - readinessProbe: - httpGet: - path: /metrics - port: zookeeperxp - initialDelaySeconds: 30 - periodSeconds: 15 - timeoutSeconds: 60 - failureThreshold: 8 - successThreshold: 1 - serviceMonitor: - interval: 30s - scrapeTimeout: 30s - scheme: http - -## ServiceMonitor configuration in case you are using Prometheus Operator -prometheus: - serviceMonitor: - ## If true a ServiceMonitor for each enabled exporter will be installed - enabled: false - ## The namespace where the ServiceMonitor(s) will be installed - # namespace: monitoring - ## The selector the Prometheus instance is searching for - ## [Default Prometheus Operator selector] (https://github.com/helm/charts/blob/f5a751f174263971fafd21eee4e35416d6612a3d/stable/prometheus-operator/templates/prometheus/prometheus.yaml#L74) - selector: {} - -## Use an alternate scheduler, e.g. "stork". -## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ -## -# schedulerName: - -## ref: https://github.com/kubernetes/contrib/tree/master/statefulsets/zookeeper -env: - - ## Options related to JMX exporter. - ## ref: https://github.com/apache/zookeeper/blob/master/bin/zkServer.sh#L36 - JMXAUTH: "false" - JMXDISABLE: "false" - JMXPORT: 1099 - JMXSSL: "false" - - ## The port on which the server will accept client requests. - ZOO_PORT: 2181 - - ## The number of Ticks that an ensemble member is allowed to perform leader - ## election. - ZOO_INIT_LIMIT: 5 - - ZOO_TICK_TIME: 2000 - - ## The maximum number of concurrent client connections that - ## a server in the ensemble will accept. - ZOO_MAX_CLIENT_CNXNS: 60 - - ## The number of Tick by which a follower may lag behind the ensembles leader. - ZK_SYNC_LIMIT: 10 - - ## The number of wall clock ms that corresponds to a Tick for the ensembles - ## internal time. - ZK_TICK_TIME: 2000 - - ZOO_AUTOPURGE_PURGEINTERVAL: 0 - ZOO_AUTOPURGE_SNAPRETAINCOUNT: 3 - ZOO_STANDALONE_ENABLED: false - -jobs: - ## ref: http://zookeeper.apache.org/doc/r3.4.10/zookeeperProgrammers.html#ch_zkSessions - chroots: - enabled: false - activeDeadlineSeconds: 300 - backoffLimit: 5 - completions: 1 - config: - create: [] - # - /kafka - # - /ureplicator - env: [] - parallelism: 1 - resources: {} - restartPolicy: Never diff --git a/deployment/deployment/nginx-ingress-controller/Chart.lock b/deployment/deployment/nginx-ingress-controller/Chart.lock deleted file mode 100644 index 90cae73..0000000 --- a/deployment/deployment/nginx-ingress-controller/Chart.lock +++ /dev/null @@ -1,6 +0,0 @@ -dependencies: -- name: common - repository: https://charts.bitnami.com/bitnami - version: 1.10.1 -digest: sha256:46a0218b2fbb421c87da91166dc5230d3ec85aa7d822dff1d479619fff8314e7 -generated: "2021-11-02T20:17:58.180110803Z" diff --git a/deployment/deployment/nginx-ingress-controller/Chart.yaml b/deployment/deployment/nginx-ingress-controller/Chart.yaml deleted file mode 100644 index 8dbb8c4..0000000 --- a/deployment/deployment/nginx-ingress-controller/Chart.yaml +++ /dev/null @@ -1,28 +0,0 @@ -annotations: - category: Infrastructure -apiVersion: v2 -appVersion: 1.1.0 -dependencies: -- name: common - repository: https://charts.bitnami.com/bitnami - tags: - - bitnami-common - version: 1.x.x -description: Chart for the nginx Ingress controller -home: https://github.com/bitnami/charts/tree/master/bitnami/nginx-ingress-controller -icon: https://bitnami.com/assets/stacks/nginx-ingress-controller/img/nginx-ingress-controller-stack-220x234.png -keywords: -- ingress -- nginx -- http -- web -- www -- reverse proxy -maintainers: -- email: containers@bitnami.com - name: Bitnami -name: nginx-ingress-controller -sources: -- https://github.com/bitnami/bitnami-docker-nginx-ingress-controller -- https://github.com/kubernetes/ingress-nginx -version: 9.0.9 diff --git a/deployment/deployment/nginx-ingress-controller/README.md b/deployment/deployment/nginx-ingress-controller/README.md deleted file mode 100644 index 6f423af..0000000 --- a/deployment/deployment/nginx-ingress-controller/README.md +++ /dev/null @@ -1,422 +0,0 @@ -# Nginx Ingress Controller - -[ingress-nginx](https://github.com/kubernetes/ingress-nginx) is an Ingress controller that uses NGINX to manage external access to HTTP services in a Kubernetes cluster. - -## TL;DR - -```bash -$ helm repo add bitnami https://charts.bitnami.com/bitnami -$ helm install my-release bitnami/nginx-ingress-controller -``` - -## Introduction - -Bitnami charts for Helm are carefully engineered, actively maintained and are the quickest and easiest way to deploy containers on a Kubernetes cluster that are ready to handle production workloads. - -This chart bootstraps a [ingress-nginx](https://github.com/kubernetes/ingress-nginx) deployment on a [Kubernetes](https://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. - -Bitnami charts can be used with [Kubeapps](https://kubeapps.com/) for deployment and management of Helm Charts in clusters. This Helm chart has been tested on top of [Bitnami Kubernetes Production Runtime](https://kubeprod.io/) (BKPR). Deploy BKPR to get automated TLS certificates, logging and monitoring for your applications. - -## Prerequisites - -- Kubernetes 1.12+ -- Helm 3.1.0 - -## Installing the Chart - -To install the chart with the release name `my-release`: - -```bash -$ helm repo add bitnami https://charts.bitnami.com/bitnami -$ helm install my-release bitnami/nginx-ingress-controller -``` - -These commands deploy nginx-ingress-controller on the Kubernetes cluster in the default configuration. - -> **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 | `[]` | - - -### Common parameters - -| Name | Description | Value | -| ------------------- | -------------------------------------------------- | ----- | -| `nameOverride` | String to partially override common.names.fullname | `""` | -| `fullnameOverride` | String to fully override common.names.fullname | `""` | -| `commonLabels` | Add labels to all the deployed resources | `{}` | -| `commonAnnotations` | Add annotations to all the deployed resources | `{}` | -| `extraDeploy` | Array of extra objects to deploy with the release | `[]` | - - -### Nginx Ingress Controller parameters - -| Name | Description | Value | -| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | -| `image.registry` | Nginx Ingress Controller image registry | `docker.io` | -| `image.repository` | Nginx Ingress Controller image repository | `bitnami/nginx-ingress-controller` | -| `image.tag` | Nginx Ingress Controller image tag (immutable tags are recommended) | `1.1.0-debian-10-r0` | -| `image.pullPolicy` | Nginx Ingress Controller image pull policy | `IfNotPresent` | -| `image.pullSecrets` | Specify docker-registry secret names as an array | `[]` | -| `containerPorts` | Controller container ports to open | `{}` | -| `hostAliases` | Deployment pod host aliases | `[]` | -| `config` | Custom configuration options for NGINX | `{}` | -| `proxySetHeaders` | Custom headers before sending traffic to backends | `{}` | -| `addHeaders` | Custom headers before sending response traffic to the client | `{}` | -| `defaultBackendService` | Default 404 backend service; required only if `defaultBackend.enabled = false` | `""` | -| `electionID` | Election ID to use for status update | `ingress-controller-leader` | -| `reportNodeInternalIp` | If using `hostNetwork=true`, setting `reportNodeInternalIp=true`, will pass the flag `report-node-internal-ip-address` to Nginx Ingress Controller | `false` | -| `watchIngressWithoutClass` | Process Ingress objects without ingressClass annotation/ingressClassName field | `false` | -| `ingressClassResource.name` | Name of the IngressClass resource | `nginx` | -| `ingressClassResource.enabled` | Create the IngressClass resource | `true` | -| `ingressClassResource.default` | Set the created IngressClass resource as default class | `false` | -| `ingressClassResource.controllerClass` | IngressClass identifier for the controller | `k8s.io/ingress-nginx` | -| `ingressClassResource.parameters` | Optional parameters for the controller | `{}` | -| `publishService.enabled` | Set the endpoint records on the Ingress objects to reflect those on the service | `false` | -| `publishService.pathOverride` | Allows overriding of the publish service to bind to | `""` | -| `scope.enabled` | Limit the scope of the controller. Defaults to `.Release.Namespace` | `false` | -| `configMapNamespace` | Allows customization of the configmap / nginx-configmap namespace | `""` | -| `tcpConfigMapNamespace` | Allows customization of the tcp-services-configmap namespace | `""` | -| `udpConfigMapNamespace` | Allows customization of the udp-services-configmap namespace | `""` | -| `maxmindLicenseKey` | License key used to download Geolite2 database | `""` | -| `dhParam` | A base64ed Diffie-Hellman parameter | `""` | -| `tcp` | TCP service key:value pairs | `{}` | -| `udp` | UDP service key:value pairs | `{}` | -| `command` | Override default container command (useful when using custom images) | `[]` | -| `args` | Override default container args (useful when using custom images) | `[]` | -| `extraArgs` | Additional command line arguments to pass to nginx-ingress-controller | `{}` | -| `extraEnvVars` | Extra environment variables to be set on Nginx Ingress container | `[]` | -| `extraEnvVarsCM` | Name of a existing ConfigMap containing extra environment variables | `""` | -| `extraEnvVarsSecret` | Name of a existing Secret containing extra environment variables | `""` | - - -### Nginx Ingress deployment / daemonset parameters - -| Name | Description | Value | -| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | -| `kind` | Install as Deployment or DaemonSet | `Deployment` | -| `daemonset.useHostPort` | If `kind` is `DaemonSet`, this will enable `hostPort` for `TCP/80` and `TCP/443` | `false` | -| `daemonset.hostPorts` | HTTP and HTTPS ports | `{}` | -| `replicaCount` | Desired number of Controller pods | `1` | -| `updateStrategy` | Strategy to use to update Pods | `{}` | -| `revisionHistoryLimit` | The number of old history to retain to allow rollback | `10` | -| `podSecurityContext.enabled` | Enable Controller pods' Security Context | `true` | -| `podSecurityContext.fsGroup` | Group ID for the container filesystem | `1001` | -| `containerSecurityContext.enabled` | Enable Controller containers' Security Context | `true` | -| `containerSecurityContext.allowPrivilegeEscalation` | Switch to allow priviledge escalation on the Controller container | `true` | -| `containerSecurityContext.runAsUser` | User ID for the Controller container | `1001` | -| `containerSecurityContext.capabilities.drop` | Linux Kernel capabilities that should be dropped | `[]` | -| `containerSecurityContext.capabilities.add` | Linux Kernel capabilities that should be added | `[]` | -| `minReadySeconds` | How many seconds a pod needs to be ready before killing the next, during update | `0` | -| `resources.limits` | The resources limits for the Controller container | `{}` | -| `resources.requests` | The requested resources for the Controller container | `{}` | -| `livenessProbe.enabled` | Enable livenessProbe | `true` | -| `livenessProbe.httpGet.path` | Request path for livenessProbe | `/healthz` | -| `livenessProbe.httpGet.port` | Port for livenessProbe | `10254` | -| `livenessProbe.httpGet.scheme` | Scheme for livenessProbe | `HTTP` | -| `livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `10` | -| `livenessProbe.periodSeconds` | Period seconds for livenessProbe | `10` | -| `livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `1` | -| `livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `3` | -| `livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | -| `readinessProbe.enabled` | Enable readinessProbe | `true` | -| `readinessProbe.httpGet.path` | Request path for readinessProbe | `/healthz` | -| `readinessProbe.httpGet.port` | Port for readinessProbe | `10254` | -| `readinessProbe.httpGet.scheme` | Scheme for readinessProbe | `HTTP` | -| `readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `10` | -| `readinessProbe.periodSeconds` | Period seconds for readinessProbe | `10` | -| `readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `1` | -| `readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `3` | -| `readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | -| `customLivenessProbe` | Override default liveness probe | `{}` | -| `customReadinessProbe` | Override default readiness probe | `{}` | -| `lifecycle` | LifecycleHooks to set additional configuration at startup | `{}` | -| `podLabels` | Extra labels for Controller pods | `{}` | -| `podAnnotations` | Annotations for Controller pods | `{}` | -| `priorityClassName` | Controller priorityClassName | `""` | -| `hostNetwork` | If the Nginx deployment / daemonset should run on the host's network namespace | `false` | -| `dnsPolicy` | By default, while using host network, name resolution uses the host's DNS | `ClusterFirst` | -| `terminationGracePeriodSeconds` | How many seconds to wait before terminating a pod | `60` | -| `podAffinityPreset` | Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `podAntiAffinityPreset` | Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `soft` | -| `nodeAffinityPreset.type` | Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `nodeAffinityPreset.key` | Node label key to match. Ignored if `affinity` is set. | `""` | -| `nodeAffinityPreset.values` | Node label values to match. Ignored if `affinity` is set. | `[]` | -| `affinity` | Affinity for pod assignment. Evaluated as a template. | `{}` | -| `nodeSelector` | Node labels for pod assignment. Evaluated as a template. | `{}` | -| `tolerations` | Tolerations for pod assignment. Evaluated as a template. | `[]` | -| `extraVolumes` | Optionally specify extra list of additional volumes for Controller pods | `[]` | -| `extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for Controller container(s) | `[]` | -| `initContainers` | Add init containers to the controller pods | `[]` | -| `sidecars` | Add sidecars to the controller pods. | `[]` | -| `customTemplate` | Override NGINX template | `{}` | -| `topologySpreadConstraints` | Topology spread constraints rely on node labels to identify the topology domain(s) that each Node is in | `[]` | -| `podSecurityPolicy.enabled` | Whether to create a PodSecurityPolicy. WARNING: PodSecurityPolicy is deprecated in Kubernetes v1.21 or later, unavailable in v1.25 or later | `false` | - - -### Default backend parameters - -| Name | Description | Value | -| --------------------------------------------------- | ----------------------------------------------------------------------------------------- | ---------------------- | -| `defaultBackend.enabled` | Enable a default backend based on NGINX | `true` | -| `defaultBackend.hostAliases` | Add deployment host aliases | `[]` | -| `defaultBackend.image.registry` | Default backend image registry | `docker.io` | -| `defaultBackend.image.repository` | Default backend image repository | `bitnami/nginx` | -| `defaultBackend.image.tag` | Default backend image tag (immutable tags are recommended) | `1.21.4-debian-10-r19` | -| `defaultBackend.image.pullPolicy` | Image pull policy | `IfNotPresent` | -| `defaultBackend.image.pullSecrets` | Specify docker-registry secret names as an array | `[]` | -| `defaultBackend.extraArgs` | Additional command line arguments to pass to Nginx container | `{}` | -| `defaultBackend.containerPort` | HTTP container port number | `8080` | -| `defaultBackend.serverBlockConfig` | NGINX backend default server block configuration | `""` | -| `defaultBackend.replicaCount` | Desired number of default backend pods | `1` | -| `defaultBackend.podSecurityContext.enabled` | Enable Default backend pods' Security Context | `true` | -| `defaultBackend.podSecurityContext.fsGroup` | Group ID for the container filesystem | `1001` | -| `defaultBackend.containerSecurityContext.enabled` | Enable Default backend containers' Security Context | `true` | -| `defaultBackend.containerSecurityContext.runAsUser` | User ID for the Default backend container | `1001` | -| `defaultBackend.resources.limits` | The resources limits for the Default backend container | `{}` | -| `defaultBackend.resources.requests` | The requested resources for the Default backend container | `{}` | -| `defaultBackend.livenessProbe.enabled` | Enable livenessProbe | `true` | -| `defaultBackend.livenessProbe.httpGet.path` | Request path for livenessProbe | `/healthz` | -| `defaultBackend.livenessProbe.httpGet.port` | Port for livenessProbe | `http` | -| `defaultBackend.livenessProbe.httpGet.scheme` | Scheme for livenessProbe | `HTTP` | -| `defaultBackend.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `30` | -| `defaultBackend.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `10` | -| `defaultBackend.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `5` | -| `defaultBackend.livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `3` | -| `defaultBackend.livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | -| `defaultBackend.readinessProbe.enabled` | Enable readinessProbe | `true` | -| `defaultBackend.readinessProbe.httpGet.path` | Request path for readinessProbe | `/healthz` | -| `defaultBackend.readinessProbe.httpGet.port` | Port for readinessProbe | `http` | -| `defaultBackend.readinessProbe.httpGet.scheme` | Scheme for readinessProbe | `HTTP` | -| `defaultBackend.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `0` | -| `defaultBackend.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `5` | -| `defaultBackend.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `5` | -| `defaultBackend.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `6` | -| `defaultBackend.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | -| `defaultBackend.podLabels` | Extra labels for Controller pods | `{}` | -| `defaultBackend.podAnnotations` | Annotations for Controller pods | `{}` | -| `defaultBackend.priorityClassName` | priorityClassName | `""` | -| `defaultBackend.podAffinityPreset` | Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `defaultBackend.podAntiAffinityPreset` | Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `soft` | -| `defaultBackend.nodeAffinityPreset.type` | Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `defaultBackend.nodeAffinityPreset.key` | Node label key to match. Ignored if `affinity` is set. | `""` | -| `defaultBackend.nodeAffinityPreset.values` | Node label values to match. Ignored if `affinity` is set. | `[]` | -| `defaultBackend.affinity` | Affinity for pod assignment | `{}` | -| `defaultBackend.nodeSelector` | Node labels for pod assignment | `{}` | -| `defaultBackend.tolerations` | Tolerations for pod assignment | `[]` | -| `defaultBackend.service.type` | Kubernetes Service type for default backend | `ClusterIP` | -| `defaultBackend.service.port` | Default backend service port | `80` | -| `defaultBackend.pdb.create` | Enable/disable a Pod Disruption Budget creation for Default backend | `false` | -| `defaultBackend.pdb.minAvailable` | Minimum number/percentage of Default backend pods that should remain scheduled | `1` | -| `defaultBackend.pdb.maxUnavailable` | Maximum number/percentage of Default backend pods that may be made unavailable | `""` | - - -### Traffic exposure parameters - -| Name | Description | Value | -| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -------------- | -| `service.type` | Kubernetes Service type for Controller | `LoadBalancer` | -| `service.ports` | Service ports | `{}` | -| `service.targetPorts` | Map the controller service HTTP/HTTPS port | `{}` | -| `service.nodePorts` | Specify the nodePort value(s) for the LoadBalancer and NodePort service types. | `{}` | -| `service.annotations` | Annotations for controller service | `{}` | -| `service.labels` | Labels for controller service | `{}` | -| `service.clusterIP` | Controller Internal Cluster Service IP (optional) | `""` | -| `service.externalIPs` | Controller Service external IP addresses | `[]` | -| `service.loadBalancerIP` | Kubernetes LoadBalancerIP to request for Controller (optional, cloud specific) | `""` | -| `service.loadBalancerSourceRanges` | List of IP CIDRs allowed access to load balancer (if supported) | `[]` | -| `service.externalTrafficPolicy` | Set external traffic policy to: "Local" to preserve source IP on providers supporting it | `""` | -| `service.healthCheckNodePort` | Set this to the managed health-check port the kube-proxy will expose. If blank, a random port in the `NodePort` range will be assigned | `0` | - - -### RBAC parameters - -| Name | Description | Value | -| ---------------------------- | ----------------------------------------------------------- | ------ | -| `serviceAccount.create` | Enable the creation of a ServiceAccount for Controller pods | `true` | -| `serviceAccount.name` | Name of the created ServiceAccount | `""` | -| `serviceAccount.annotations` | Annotations for service account. | `{}` | -| `rbac.create` | Specifies whether RBAC rules should be created | `true` | - - -### Other parameters - -| Name | Description | Value | -| -------------------------- | ------------------------------------------------------------------------- | ------- | -| `pdb.create` | Enable/disable a Pod Disruption Budget creation for Controller | `false` | -| `pdb.minAvailable` | Minimum number/percentage of Controller pods that should remain scheduled | `1` | -| `pdb.maxUnavailable` | Maximum number/percentage of Controller pods that may be made unavailable | `""` | -| `autoscaling.enabled` | Enable autoscaling for Controller | `false` | -| `autoscaling.minReplicas` | Minimum number of Controller replicas | `1` | -| `autoscaling.maxReplicas` | Maximum number of Controller replicas | `11` | -| `autoscaling.targetCPU` | Target CPU utilization percentage | `""` | -| `autoscaling.targetMemory` | Target Memory utilization percentage | `""` | - - -### Metrics parameters - -| Name | Description | Value | -| ----------------------------------------- | ----------------------------------------------------------------------------- | ----------- | -| `metrics.enabled` | Enable exposing Controller statistics | `false` | -| `metrics.service.type` | Type of Prometheus metrics service to create | `ClusterIP` | -| `metrics.service.port` | Service HTTP management port | `9913` | -| `metrics.service.annotations` | Annotations for the Prometheus exporter service | `{}` | -| `metrics.serviceMonitor.enabled` | Create ServiceMonitor resource for scraping metrics using PrometheusOperator | `false` | -| `metrics.serviceMonitor.namespace` | Namespace in which Prometheus is running | `""` | -| `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.selector` | ServiceMonitor selector labels | `{}` | -| `metrics.prometheusRule.enabled` | Create PrometheusRules resource for scraping metrics using PrometheusOperator | `false` | -| `metrics.prometheusRule.additionalLabels` | Used to pass Labels that are required by the Installed Prometheus Operator | `{}` | -| `metrics.prometheusRule.namespace` | Namespace which Prometheus is running in | `""` | -| `metrics.prometheusRule.rules` | Rules to be prometheus in YAML format, check values for an example | `[]` | - - -Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, - -```bash -$ helm install my-release \ - --set image.pullPolicy=Always \ - bitnami/nginx-ingress-controller -``` - -The above command sets the `image.pullPolicy` to `Always`. - -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 bitnami/nginx-ingress-controller -``` - -> **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. - -### Sidecars and Init Containers - -If you have a need for additional containers to run within the same pod as the NGINX Ingress Controller (e.g. an additional metrics or logging exporter), you can do so via the `sidecars` config parameter. Simply define your container according to the Kubernetes container spec. - -```yaml -sidecars: - - name: your-image-name - image: your-image - imagePullPolicy: Always - ports: - - name: portname - containerPort: 1234 -``` - -Similarly, you can add extra init containers using the `initContainers` parameter. - -```yaml -initContainers: - - name: your-image-name - image: your-image - imagePullPolicy: Always - ports: - - name: portname - containerPort: 1234 -``` - -### Deploying extra resources - -There are cases where you may want to deploy extra objects, such a ConfigMap containing your app's configuration or some extra deployment with a micro service used by your app. For covering this case, the chart allows adding the full specification of other objects using the `extraDeploy` parameter. - -### Setting Pod's affinity - -This chart allows you to set your custom affinity using the `affinity` parameter. Find more information about Pod's affinity in the [kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity). - -As an alternative, you can use of the preset configurations for pod affinity, pod anti-affinity, and node affinity available at the [bitnami/common](https://github.com/bitnami/charts/tree/master/bitnami/common#affinities) chart. To do so, set the `podAffinityPreset`, `podAntiAffinityPreset`, or `nodeAffinityPreset` parameters. - -## 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). - -## Notable changes - -### 5.3.0 - -In this version you can indicate the key to download the GeoLite2 databases using the [parameter](#parameters) `maxmindLicenseKey`. - -## Upgrading - -### To 9.0.0 - -- Configuration for routing `Ingress` resources with custom `kubernetes.io/ingress.class` annotation is changed in favor of `IngressClass` resource required in NGINX Ingress Controller 1.x - - `ingressClass` parameter is removed and replaced with `ingressClassResource.*` parameters - - `ingressClassResource.*` parameters configure `IngressClass` resource only - - To configure routing for `Ingress` using custom `kubernetes.io/ingress.class` annotation define `extraArgs.ingress-class` parameter with the annotation value - -Consequences: - -- Backwards compatibility is not guaranteed. Uninstall & install the chart again to obtain the latest version. - -### To 7.0.0 - -- Chart labels were adapted to follow the [Helm charts standard labels](https://helm.sh/docs/chart_best_practices/labels/#standard-labels). -- Several parameters were renamed or disappeared in favor of new ones on this major version. These are a few examples: - - `*.securityContext` paramateres are deprecated in favor of `*.containerSecurityContext` ones. - - `*.minAvailable` paramateres are deprecated in favor of `*.pdb.minAvailable` ones. - - `extraContainers` paramatere is deprecated in favor of `sidecars`. -- 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/master/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. Uninstall & install the chart again to obtain the latest version. - -### To 6.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. -- 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/ - -### To 1.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 1.0.0. The following example assumes that the release name is nginx-ingress-controller: - -```console -$ kubectl patch deployment nginx-ingress-controller-default-backend --type=json -p='[{"op": "remove", "path": "/spec/selector/matchLabels/chart"}]' -# If using deployments -$ kubectl patch deployment nginx-ingress-controller --type=json -p='[{"op": "remove", "path": "/spec/selector/matchLabels/chart"}]' -# If using daemonsets -$ kubectl patch daemonset nginx-ingress-controller --type=json -p='[{"op": "remove", "path": "/spec/selector/matchLabels/chart"}]' -``` diff --git a/deployment/deployment/nginx-ingress-controller/ci/ct-values.yaml b/deployment/deployment/nginx-ingress-controller/ci/ct-values.yaml deleted file mode 100644 index b738e2a..0000000 --- a/deployment/deployment/nginx-ingress-controller/ci/ct-values.yaml +++ /dev/null @@ -1,2 +0,0 @@ -service: - type: ClusterIP diff --git a/deployment/deployment/nginx-ingress-controller/ci/values-production-with-psp.yaml b/deployment/deployment/nginx-ingress-controller/ci/values-production-with-psp.yaml deleted file mode 100644 index ff2245b..0000000 --- a/deployment/deployment/nginx-ingress-controller/ci/values-production-with-psp.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Test values file for generating all of the yaml and check that -# the rendering is correct - -kind: DaemonSet - -podSecurityPolicy: - enabled: true - -metrics: - enabled: true - ## Kubeval doesn't recognise ServiceMonitor as a valid K8s object - # serviceMonitor: - # enabled: true diff --git a/deployment/deployment/nginx-ingress-controller/templates/NOTES.txt b/deployment/deployment/nginx-ingress-controller/templates/NOTES.txt deleted file mode 100644 index e299b7b..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/NOTES.txt +++ /dev/null @@ -1,93 +0,0 @@ -CHART NAME: {{ .Chart.Name }} -CHART VERSION: {{ .Chart.Version }} -APP VERSION: {{ .Chart.AppVersion }} - -** Please be patient while the chart is being deployed ** - -The nginx-ingress controller has been installed. - -Get the application URL by running these commands: - -{{- $httpPort := .Values.service.ports.http | toString }} -{{- $httpsPort := .Values.service.ports.https | toString }} - -{{- if contains "NodePort" .Values.service.type }} -{{- if (not (empty .Values.service.nodePorts.http)) }} - export HTTP_NODE_PORT={{ .Values.service.nodePorts.http }} -{{- else }} - export HTTP_NODE_PORT=$(kubectl --namespace {{ .Release.Namespace }} get services -o jsonpath="{.spec.ports[0].nodePort}" {{ template "common.names.fullname" . }}) -{{- end }} -{{- if (not (empty .Values.service.nodePorts.https)) }} - export HTTPS_NODE_PORT={{ .Values.service.nodePorts.https }} -{{- else }} - export HTTPS_NODE_PORT=$(kubectl --namespace {{ .Release.Namespace }} get services -o jsonpath="{.spec.ports[1].nodePort}" {{ template "common.names.fullname" . }}) -{{- end }} - export NODE_IP=$(kubectl --namespace {{ .Release.Namespace }} get nodes -o jsonpath="{.items[0].status.addresses[1].address}") - - echo "Visit http://$NODE_IP:$HTTP_NODE_PORT to access your application via HTTP." - echo "Visit https://$NODE_IP:$HTTPS_NODE_PORT to access your application via HTTPS." - -{{- else if contains "LoadBalancer" .Values.service.type }} - - NOTE: It may take a few minutes for the LoadBalancer IP to be available. - You can watch its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "common.names.fullname" . }}' - - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "common.names.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') - echo "Visit http://${SERVICE_IP}{{- if ne $httpPort "80" }}:{{ $httpPort }}{{ end }} to access your application via HTTP." - echo "Visit https://${SERVICE_IP}{{- if ne $httpsPort "443" }}:{{ $httpsPort }}{{ end }} to access your application via HTTPS." - -{{- else if contains "ClusterIP" .Values.service.type }} - - kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ include "common.names.fullname" . }} ${SERVICE_PORT}:${SERVICE_PORT} & - echo "Visit http://127.0.0.1:{{- if ne $httpPort "80" }}:{{ $httpPort }}{{ end }}to access your application via HTTP." - echo "Visit https://127.0.0.1:{{- if ne $httpsPort "443" }}:{{ $httpsPort }}{{ end }} to access your application via HTTPS." - -{{- end }} - -An example Ingress that makes use of the controller: - - apiVersion: networking.k8s.io/v1 - kind: Ingress - metadata: - name: example - namespace: {{ .Release.Namespace }} - spec: - ingressClassName: {{ .Values.ingressClassResource.name }} - rules: - - host: www.example.com - http: - paths: - - backend: - service: - name: example-service - port: - number: 80 - path: / - pathType: Prefix - # This section is only required if TLS is to be enabled for the Ingress - tls: - - hosts: - - www.example.com - secretName: example-tls - -If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided: - - apiVersion: v1 - kind: Secret - metadata: - name: example-tls - namespace: {{ .Release.Namespace }} - data: - tls.crt: - tls.key: - type: kubernetes.io/tls - -{{- if .Values.headers }} -################################################################################# -###### WARNING: `controller.headers` has been deprecated! ##### -###### It has been renamed to `controller.proxySetHeaders`. ##### -################################################################################# -{{- end }} - -{{- include "common.warnings.rollingTag" .Values.image }} -{{- include "common.warnings.rollingTag" .Values.defaultBackend.image }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/_helpers.tpl b/deployment/deployment/nginx-ingress-controller/templates/_helpers.tpl deleted file mode 100644 index 8716b5d..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/_helpers.tpl +++ /dev/null @@ -1,75 +0,0 @@ -{{/* vim: set filetype=mustache: */}} - -{{/* -Create a default fully qualified default backend name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -*/}} -{{- define "nginx-ingress-controller.defaultBackend.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- printf "%s-default-backend" .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- printf "%s-default-backend" .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s-default-backend" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Return the proper nginx-ingress-controller image name -*/}} -{{- define "nginx-ingress-controller.image" -}} -{{ include "common.images.image" (dict "imageRoot" .Values.image "global" .Values.global) }} -{{- end -}} - -{{/* -Return the proper defaultBackend image name -*/}} -{{- define "nginx-ingress-controller.defaultBackend.image" -}} -{{ include "common.images.image" (dict "imageRoot" .Values.defaultBackend.image "global" .Values.global) }} -{{- end -}} - -{{/* -Return the proper Docker Image Registry Secret Names -*/}} -{{- define "nginx-ingress-controller.imagePullSecrets" -}} -{{- include "common.images.pullSecrets" (dict "images" (list .Values.image .Values.defaultBackend.image) "global" .Values.global) -}} -{{- end -}} - -{{/* -Construct the path for the publish-service. - -By convention this will simply use the / to match the name of the -service generated. -Users can provide an override for an explicit service they want bound via `.Values.publishService.pathOverride` - -*/}} -{{- define "nginx-ingress-controller.publishServicePath" -}} -{{- $defServiceName := printf "%s/%s" .Release.Namespace (include "common.names.fullname" .) -}} -{{- $servicePath := default $defServiceName .Values.publishService.pathOverride }} -{{- print $servicePath | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create the name of the service account to use -*/}} -{{- define "nginx-ingress-controller.serviceAccountName" -}} -{{- if .Values.serviceAccount.create -}} - {{ default (include "common.names.fullname" .) .Values.serviceAccount.name }} -{{- else -}} - {{ default "default" .Values.serviceAccount.name }} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiGroup for PodSecurityPolicy. -*/}} -{{- define "nginx-ingress-controller.podSecurityPolicy.apiGroup" -}} -{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} -{{- print "policy" -}} -{{- else -}} -{{- print "extensions" -}} -{{- end -}} -{{- end -}} diff --git a/deployment/deployment/nginx-ingress-controller/templates/addheaders-configmap.yaml b/deployment/deployment/nginx-ingress-controller/templates/addheaders-configmap.yaml deleted file mode 100644 index 6772586..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/addheaders-configmap.yaml +++ /dev/null @@ -1,16 +0,0 @@ -{{- if .Values.addHeaders }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ printf "%s-custom-add-headers" (include "common.names.fullname" .) }} - namespace: {{ .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: controller - {{- 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: {{- include "common.tplvalues.render" (dict "value" .Values.addHeaders "context" $ ) | nindent 2 }} -{{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/clusterrole.yaml b/deployment/deployment/nginx-ingress-controller/templates/clusterrole.yaml deleted file mode 100644 index df901b9..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/clusterrole.yaml +++ /dev/null @@ -1,83 +0,0 @@ -{{- if and .Values.rbac.create (not .Values.scope.enabled) -}} -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: ClusterRole -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: - - configmaps - - endpoints - - nodes - - pods - - secrets - verbs: - - list - - watch - {{- if and .Values.scope.enabled .Values.scope.namespace }} - - apiGroups: - - "" - resources: - - namespaces - resourceNames: - - "{{ .Values.scope.namespace }}" - verbs: - - get - {{- end }} - - apiGroups: - - "" - resources: - - nodes - verbs: - - get - - apiGroups: - - "" - resources: - - services - verbs: - - get - - list - - update - - watch - - apiGroups: - - extensions - - networking.k8s.io - resources: - - ingresses - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch - - apiGroups: - - extensions - - networking.k8s.io - resources: - - ingresses/status - verbs: - - update - - apiGroups: - - extensions - - networking.k8s.io - resources: - - ingressclasses - verbs: - - get - - list - - watch -{{- end -}} diff --git a/deployment/deployment/nginx-ingress-controller/templates/controller-configmap.yaml b/deployment/deployment/nginx-ingress-controller/templates/controller-configmap.yaml deleted file mode 100644 index 9f46023..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/controller-configmap.yaml +++ /dev/null @@ -1,28 +0,0 @@ -{{- if or .Values.config (or (or .Values.proxySetHeaders .Values.headers) .Values.addHeaders) .Values.dhParam }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "common.names.fullname" . }} - namespace: {{ .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: controller - {{- 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: - {{- if .Values.addHeaders }} - add-headers: {{ .Release.Namespace }}/{{ printf "%s-custom-add-headers" (include "common.names.fullname" .) }} - {{- end }} - {{- if or .Values.proxySetHeaders .Values.headers }} - proxy-set-headers: {{ .Release.Namespace }}/{{ printf "%s-custom-proxy-headers" (include "common.names.fullname" .) }} - {{- end }} - {{- if .Values.dhParam }} - ssl-dh-param: {{ printf "%s/%s" .Release.Namespace (include "common.names.fullname" .) }} - {{- end }} - {{- if .Values.config }} - {{- include "common.tplvalues.render" (dict "value" .Values.config "context" $) | nindent 2 }} - {{- end }} -{{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/controller-daemonset.yaml b/deployment/deployment/nginx-ingress-controller/templates/controller-daemonset.yaml deleted file mode 100644 index f5a7726..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/controller-daemonset.yaml +++ /dev/null @@ -1,221 +0,0 @@ -{{- if eq .Values.kind "DaemonSet" }} -{{- $useHostPort := .Values.daemonset.useHostPort -}} -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: controller - {{- 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: - selector: - matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} - app.kubernetes.io/component: controller - revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} - {{- if .Values.updateStrategy }} - updateStrategy: {{- toYaml .Values.updateStrategy | nindent 4 }} - {{- end }} - minReadySeconds: {{ .Values.minReadySeconds }} - template: - metadata: - {{- if .Values.podAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.podAnnotations "context" $ ) | nindent 8 }} - {{- end }} - labels: {{- include "common.labels.standard" . | nindent 8 }} - app.kubernetes.io/component: controller - {{- if .Values.podLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.podLabels "context" $) | nindent 8 }} - {{- end }} - spec: - {{- include "nginx-ingress-controller.imagePullSecrets" . | nindent 6 }} - dnsPolicy: {{ .Values.dnsPolicy }} - {{- if .Values.priorityClassName }} - priorityClassName: {{ .Values.priorityClassName | quote }} - {{- end }} - {{- if .Values.hostAliases }} - hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.hostAliases "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.affinity }} - affinity: {{- include "common.tplvalues.render" ( dict "value" .Values.affinity "context" $) | nindent 8 }} - {{- else }} - affinity: - podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAffinityPreset "component" "controller" "context" $) | nindent 10 }} - podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset "component" "controller" "context" $) | nindent 10 }} - nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.nodeAffinityPreset.type "key" .Values.nodeAffinityPreset.key "values" .Values.nodeAffinityPreset.values) | nindent 10 }} - {{- end }} - {{- if .Values.nodeSelector }} - nodeSelector: {{- include "common.tplvalues.render" ( dict "value" .Values.nodeSelector "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.tolerations }} - tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.tolerations "context" .) | nindent 8 }} - {{- end }} - {{- if .Values.podSecurityContext.enabled }} - securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} - {{- end }} - hostNetwork: {{ .Values.hostNetwork }} - {{- if .Values.topologySpreadConstraints }} - topologySpreadConstraints: {{- toYaml .Values.topologySpreadConstraints | nindent 8 }} - {{- end }} - serviceAccountName: {{ template "nginx-ingress-controller.serviceAccountName" . }} - terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} - {{- if .Values.initContainers }} - initContainers: {{- toYaml .Values.initContainers | nindent 8 }} - {{- end }} - containers: - - name: controller - image: {{ include "nginx-ingress-controller.image" . }} - imagePullPolicy: {{ .Values.image.pullPolicy | quote }} - {{- if .Values.containerSecurityContext.enabled }} - # yamllint disable rule:indentation - securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} - # yamllint enable rule:indentation - {{- end }} - {{- if .Values.lifecycle }} - lifecycle: {{- toYaml .Values.lifecycle | nindent 12 }} - {{- end }} - {{- if .Values.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.command "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.args }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.args "context" $) | nindent 12 }} - {{- else }} - args: - - /nginx-ingress-controller - - --default-backend-service={{ if .Values.defaultBackend.enabled }}{{ .Release.Namespace }}/{{ include "nginx-ingress-controller.defaultBackend.fullname" . }}{{ else }}{{ .Values.defaultBackendService }}{{ end }} - {{- if .Values.publishService.enabled }} - - --publish-service={{ include "nginx-ingress-controller.publishServicePath" . }} - {{- end }} - - --election-id={{ .Values.electionID }} - - --controller-class={{ .Values.ingressClassResource.controllerClass }} - - --configmap={{ .Release.Namespace }}/{{ include "common.names.fullname" . }} - {{- if .Values.tcp }} - - --tcp-services-configmap={{ .Release.Namespace }}/{{ include "common.names.fullname" . }}-tcp - {{- end }} - {{- if .Values.udp }} - - --udp-services-configmap={{ .Release.Namespace }}/{{ include "common.names.fullname" . }}-udp - {{- end }} - {{- if .Values.scope.enabled }} - - --watch-namespace={{ default .Release.Namespace .Values.scope.namespace }} - {{- end }} - {{- if .Values.maxmindLicenseKey }} - - --maxmind-license-key={{ .Values.maxmindLicenseKey }} - {{- end }} - {{- if and (.Values.reportNodeInternalIp) (.Values.hostNetwork)}} - - --report-node-internal-ip-address={{ .Values.reportNodeInternalIp }} - {{- end }} - {{- if .Values.watchIngressWithoutClass }} - - --watch-ingress-without-class=true - {{- end }} - {{- range $key, $value := .Values.extraArgs }} - {{- if $value }} - - --{{ $key }}={{ $value }} - {{- else }} - - --{{ $key }} - {{- end }} - {{- end }} - {{- end }} - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - {{- if .Values.extraEnvVars }} - {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - {{- if or .Values.extraEnvVarsCM .Values.extraEnvVarsSecret }} - envFrom: - {{- if .Values.extraEnvVarsCM }} - - configMapRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsCM "context" $) }} - {{- end }} - {{- if .Values.extraEnvVarsSecret }} - - secretRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsSecret "context" $) }} - {{- end }} - {{- end }} - {{- if .Values.livenessProbe.enabled }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.livenessProbe "enabled") "context" $) | nindent 12 }} - {{- else if .Values.customLivenessProbe }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customLivenessProbe "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.readinessProbe.enabled }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.readinessProbe "enabled") "context" $) | nindent 12 }} - {{- else if .Values.customReadinessProbe }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 12 }} - {{- end }} - ports: - - name: http - containerPort: {{ .Values.containerPorts.http }} - protocol: TCP - {{- if $useHostPort }} - hostPort: {{ .Values.daemonset.hostPorts.http }} - {{- end }} - - name: https - containerPort: {{ .Values.containerPorts.https }} - protocol: TCP - {{- if $useHostPort }} - hostPort: {{ .Values.daemonset.hostPorts.https }} - {{- end }} - {{- if .Values.metrics.enabled }} - - name: metrics - containerPort: {{ .Values.containerPorts.metrics }} - protocol: TCP - {{- end }} - {{- range $key, $value := .Values.tcp }} - - name: "{{ $key }}-tcp" - containerPort: {{ $key }} - protocol: TCP - {{- if $useHostPort }} - hostPort: {{ $key }} - {{- end }} - {{- end }} - {{- range $key, $value := .Values.udp }} - - name: "{{ $key }}-udp" - containerPort: {{ $key }} - protocol: UDP - {{- if $useHostPort }} - hostPort: {{ $key }} - {{- end }} - {{- end }} - {{- if .Values.resources }} - resources: {{- toYaml .Values.resources | nindent 12 }} - {{- end }} - {{- if or .Values.customTemplate.configMapName .Values.extraVolumeMounts }} - volumeMounts: - {{- if .Values.customTemplate.configMapName }} - - mountPath: /etc/nginx/template - name: nginx-template-volume - readOnly: true - {{- end }} - {{- if .Values.extraVolumeMounts }} - {{- include "common.tplvalues.render" (dict "value" .Values.extraVolumeMounts "context" $) | nindent 12 }} - {{- end }} - {{- end }} - {{- if .Values.sidecars }} - {{- include "common.tplvalues.render" ( dict "value" .Values.sidecars "context" $) | nindent 8 }} - {{- end }} - {{- if (or .Values.customTemplate.configMapName .Values.extraVolumes) }} - volumes: - {{- if .Values.customTemplate.configMapName }} - - name: nginx-template-volume - configMap: - name: {{ .Values.customTemplate.configMapName }} - items: - - key: {{ .Values.customTemplate.configMapKey }} - path: nginx.tmpl - {{- end }} - {{- if .Values.extraVolumes }} - {{- include "common.tplvalues.render" (dict "value" .Values.extraVolumes "context" $) | nindent 8 }} - {{- end }} - {{- end }} -{{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/controller-deployment.yaml b/deployment/deployment/nginx-ingress-controller/templates/controller-deployment.yaml deleted file mode 100644 index 0828983..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/controller-deployment.yaml +++ /dev/null @@ -1,211 +0,0 @@ -{{- if eq .Values.kind "Deployment" }} -apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} -kind: Deployment -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: controller - {{- 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: - selector: - matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} - app.kubernetes.io/component: controller - {{- if not .Values.autoscaling.enabled }} - replicas: {{ .Values.replicaCount }} - {{- end }} - revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} - {{- if .Values.updateStrategy }} - strategy: {{- toYaml .Values.updateStrategy | nindent 4 }} - {{- end }} - minReadySeconds: {{ .Values.minReadySeconds }} - template: - metadata: - {{- if .Values.podAnnotations }} - annotations: {{- include "common.tplvalues.render" (dict "value" .Values.podAnnotations "context" $) | nindent 8 }} - {{- end }} - labels: {{- include "common.labels.standard" . | nindent 8 }} - app.kubernetes.io/component: controller - {{- if .Values.podLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.podLabels "context" $) | nindent 8 }} - {{- end }} - spec: - {{- include "nginx-ingress-controller.imagePullSecrets" . | nindent 6 }} - dnsPolicy: {{ .Values.dnsPolicy }} - {{- if .Values.priorityClassName }} - priorityClassName: {{ .Values.priorityClassName | quote }} - {{- end }} - {{- if .Values.hostAliases }} - hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.hostAliases "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.affinity }} - affinity: {{- include "common.tplvalues.render" ( dict "value" .Values.affinity "context" $) | nindent 8 }} - {{- else }} - affinity: - podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAffinityPreset "component" "controller" "context" $) | nindent 10 }} - podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset "component" "controller" "context" $) | nindent 10 }} - nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.nodeAffinityPreset.type "key" .Values.nodeAffinityPreset.key "values" .Values.nodeAffinityPreset.values) | nindent 10 }} - {{- end }} - {{- if .Values.nodeSelector }} - nodeSelector: {{- include "common.tplvalues.render" ( dict "value" .Values.nodeSelector "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.tolerations }} - tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.tolerations "context" .) | nindent 8 }} - {{- end }} - {{- if .Values.podSecurityContext.enabled }} - securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} - {{- end }} - hostNetwork: {{ .Values.hostNetwork }} - {{- if .Values.topologySpreadConstraints }} - topologySpreadConstraints: {{- toYaml .Values.topologySpreadConstraints | nindent 8 }} - {{- end }} - serviceAccountName: {{ template "nginx-ingress-controller.serviceAccountName" . }} - terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} - {{- if .Values.initContainers }} - initContainers: {{- toYaml .Values.initContainers | nindent 8 }} - {{- end }} - containers: - - name: controller - image: {{ include "nginx-ingress-controller.image" . }} - imagePullPolicy: {{ .Values.image.pullPolicy | quote }} - {{- if .Values.containerSecurityContext.enabled }} - # yamllint disable rule:indentation - securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} - # yamllint enable rule:indentation - {{- end }} - {{- if .Values.lifecycle }} - lifecycle: {{- toYaml .Values.lifecycle | nindent 12 }} - {{- end }} - {{- if .Values.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.command "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.args }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.args "context" $) | nindent 12 }} - {{- else }} - args: - - /nginx-ingress-controller - - --default-backend-service={{ if .Values.defaultBackend.enabled }}{{ .Release.Namespace }}/{{ include "nginx-ingress-controller.defaultBackend.fullname" . }}{{ else }}{{ .Values.defaultBackendService }}{{ end }} - {{- if .Values.publishService.enabled }} - - --publish-service={{ include "nginx-ingress-controller.publishServicePath" . }} - {{- end }} - - --election-id={{ .Values.electionID }} - - --controller-class={{ .Values.ingressClassResource.controllerClass }} - - --configmap={{ default .Release.Namespace .Values.configMapNamespace }}/{{ include "common.names.fullname" . }} - {{- if .Values.tcp }} - - --tcp-services-configmap={{ default .Release.Namespace .Values.tcpConfigMapNamespace }}/{{ include "common.names.fullname" . }}-tcp - {{- end }} - {{- if .Values.udp }} - - --udp-services-configmap={{ default .Release.Namespace .Values.udpConfigMapNamespace }}/{{ include "common.names.fullname" . }}-udp - {{- end }} - {{- if .Values.scope.enabled }} - - --watch-namespace={{ default .Release.Namespace .Values.scope.namespace }} - {{- end }} - {{- if .Values.maxmindLicenseKey }} - - --maxmind-license-key={{ .Values.maxmindLicenseKey }} - {{- end }} - {{- if and (.Values.reportNodeInternalIp) (.Values.hostNetwork) }} - - --report-node-internal-ip-address={{ .Values.reportNodeInternalIp }} - {{- end }} - {{- if .Values.watchIngressWithoutClass }} - - --watch-ingress-without-class=true - {{- end }} - {{- range $key, $value := .Values.extraArgs }} - {{- if $value }} - - --{{ $key }}={{ $value }} - {{- else }} - - --{{ $key }} - {{- end }} - {{- end }} - {{- end }} - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - {{- if .Values.extraEnvVars }} - {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - {{- if or .Values.extraEnvVarsCM .Values.extraEnvVarsSecret }} - envFrom: - {{- if .Values.extraEnvVarsCM }} - - configMapRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsCM "context" $) }} - {{- end }} - {{- if .Values.extraEnvVarsSecret }} - - secretRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsSecret "context" $) }} - {{- end }} - {{- end }} - {{- if .Values.livenessProbe.enabled }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.livenessProbe "enabled") "context" $) | nindent 12 }} - {{- else if .Values.customLivenessProbe }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customLivenessProbe "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.readinessProbe.enabled }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.readinessProbe "enabled") "context" $) | nindent 12 }} - {{- else if .Values.customReadinessProbe }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 12 }} - {{- end }} - ports: - - name: http - containerPort: {{ .Values.containerPorts.http }} - protocol: TCP - - name: https - containerPort: {{ .Values.containerPorts.https }} - protocol: TCP - {{- if .Values.metrics.enabled }} - - name: metrics - containerPort: {{ .Values.containerPorts.metrics }} - protocol: TCP - {{- end }} - {{- range $key, $value := .Values.tcp }} - - name: "{{ $key }}-tcp" - containerPort: {{ $key }} - protocol: TCP - {{- end }} - {{- range $key, $value := .Values.udp }} - - name: "{{ $key }}-udp" - containerPort: {{ $key }} - protocol: UDP - {{- end }} - {{- if .Values.resources }} - resources: {{- toYaml .Values.resources | nindent 12 }} - {{- end }} - {{- if or .Values.customTemplate.configMapName .Values.extraVolumeMounts }} - volumeMounts: - {{- if .Values.customTemplate.configMapName }} - - mountPath: /etc/nginx/template - name: nginx-template-volume - readOnly: true - {{- end }} - {{- if .Values.extraVolumeMounts }} - {{- include "common.tplvalues.render" (dict "value" .Values.extraVolumeMounts "context" $) | nindent 12 }} - {{- end }} - {{- end }} - {{- if .Values.sidecars }} - {{- include "common.tplvalues.render" ( dict "value" .Values.sidecars "context" $) | nindent 8 }} - {{- end }} - {{- if (or .Values.customTemplate.configMapName .Values.extraVolumes) }} - volumes: - {{- if .Values.customTemplate.configMapName }} - - name: nginx-template-volume - configMap: - name: {{ .Values.customTemplate.configMapName }} - items: - - key: {{ .Values.customTemplate.configMapKey }} - path: nginx.tmpl - {{- end }} - {{- if .Values.extraVolumes }} - {{- include "common.tplvalues.render" (dict "value" .Values.extraVolumes "context" $) | nindent 8 }} - {{- end }} - {{- end }} -{{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/controller-hpa.yaml b/deployment/deployment/nginx-ingress-controller/templates/controller-hpa.yaml deleted file mode 100644 index 4bb9ae6..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/controller-hpa.yaml +++ /dev/null @@ -1,35 +0,0 @@ -{{- if and .Values.autoscaling.enabled (eq .Values.kind "Deployment") }} -apiVersion: autoscaling/v2beta1 -kind: HorizontalPodAutoscaler -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: controller - {{- 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: - scaleTargetRef: - apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} - kind: Deployment - name: {{ template "common.names.fullname" . }} - minReplicas: {{ .Values.autoscaling.minReplicas }} - maxReplicas: {{ .Values.autoscaling.maxReplicas }} - metrics: - {{- if .Values.autoscaling.targetMemory }} - - type: Resource - resource: - name: memory - targetAverageUtilization: {{ .Values.autoscaling.targetMemory }} - {{- end }} - {{- if .Values.autoscaling.targetCPU }} - - type: Resource - resource: - name: cpu - targetAverageUtilization: {{ .Values.autoscaling.targetCPU }} - {{- end }} -{{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/controller-service.yaml b/deployment/deployment/nginx-ingress-controller/templates/controller-service.yaml deleted file mode 100644 index 7c97e57..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/controller-service.yaml +++ /dev/null @@ -1,89 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: controller - {{- if .Values.service.labels }} - {{- include "common.tplvalues.render" (dict "value" .Values.service.labels "context" $) | nindent 4 }} - {{- end }} - {{- if .Values.commonLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} - {{- end }} - {{- if or .Values.service.annotations .Values.commonAnnotations }} - annotations: - {{- if .Values.commonAnnotations }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} - {{- end }} - {{- if .Values.service.annotations }} - {{- include "common.tplvalues.render" (dict "value" .Values.service.annotations "context" $) | nindent 4 }} - {{- end }} - {{- end }} -spec: - type: {{ .Values.service.type }} - {{- if not (empty .Values.service.clusterIP) }} - clusterIP: {{ .Values.service.clusterIP | quote }} - {{- end }} - {{- if .Values.service.externalIPs }} - externalIPs: {{- toYaml .Values.service.externalIPs | nindent 4 }} - {{- end }} - {{- if .Values.service.loadBalancerIP }} - loadBalancerIP: {{ .Values.service.loadBalancerIP | quote }} - {{- end }} - {{- if .Values.service.loadBalancerSourceRanges }} - loadBalancerSourceRanges: {{- toYaml .Values.service.loadBalancerSourceRanges | nindent 4 }} - {{- end }} - {{- if .Values.service.externalTrafficPolicy }} - externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy | quote }} - {{- end }} - {{- if .Values.service.healthCheckNodePort }} - healthCheckNodePort: {{ .Values.service.healthCheckNodePort }} - {{- end }} - ports: - {{- if not (empty .Values.service.ports.http) }} - - name: http - port: {{ .Values.service.ports.http }} - protocol: TCP - targetPort: {{ .Values.service.targetPorts.http }} - {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.http)) }} - nodePort: {{ .Values.service.nodePorts.http }} - {{- else if eq .Values.service.type "ClusterIP" }} - nodePort: null - {{- end }} - {{- end }} - {{- if not (empty .Values.service.ports.https) }} - - name: https - port: {{ .Values.service.ports.https }} - protocol: TCP - targetPort: {{ .Values.service.targetPorts.https }} - {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.https)) }} - nodePort: {{ .Values.service.nodePorts.https }} - {{- else if eq .Values.service.type "ClusterIP" }} - nodePort: null - {{- end }} - {{- end }} - {{- range $key, $value := .Values.tcp }} - - name: {{ $key }}-tcp - port: {{ $key }} - protocol: TCP - targetPort: {{ $key }}-tcp - {{- if and (or (eq $.Values.service.type "NodePort") (eq $.Values.service.type "LoadBalancer")) (index $.Values.service.nodePorts.tcp $key) }} - nodePort: {{ index $.Values.service.nodePorts.tcp $key }} - {{- else if eq $.Values.service.type "ClusterIP" }} - nodePort: null - {{- end }} - {{- end }} - {{- range $key, $value := .Values.udp }} - - name: {{ $key }}-udp - port: {{ $key }} - protocol: UDP - targetPort: {{ $key }}-udp - {{- if and (or (eq $.Values.service.type "NodePort") (eq $.Values.service.type "LoadBalancer")) (index $.Values.service.nodePorts.udp $key) }} - nodePort: {{ index $.Values.service.nodePorts.udp $key }} - {{- else if eq $.Values.service.type "ClusterIP" }} - nodePort: null - {{- end }} - {{- end }} - selector: {{- include "common.labels.matchLabels" . | nindent 4 }} - app.kubernetes.io/component: controller diff --git a/deployment/deployment/nginx-ingress-controller/templates/controller-servicemonitor.yaml b/deployment/deployment/nginx-ingress-controller/templates/controller-servicemonitor.yaml deleted file mode 100644 index df6d14d..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/controller-servicemonitor.yaml +++ /dev/null @@ -1,38 +0,0 @@ -{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: {{ template "common.names.fullname" . }} - {{- if .Values.metrics.serviceMonitor.namespace }} - namespace: {{ .Values.metrics.serviceMonitor.namespace | quote }} - {{- else }} - namespace: {{ .Release.Namespace | quote }} - {{- end }} - labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: metrics - {{- if .Values.metrics.serviceMonitor.additionalLabels }} - {{- toYaml .Values.metrics.serviceMonitor.additionalLabels | nindent 4 }} - {{- end }} - {{- 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: - endpoints: - - port: metrics - interval: {{ .Values.metrics.serviceMonitor.interval }} - {{- if .Values.metrics.serviceMonitor.honorLabels }} - honorLabels: true - {{- end }} - {{- if .Values.metrics.serviceMonitor.metricRelabelings }} - metricRelabelings: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.metricRelabelings "context" $) | nindent 8 }} - {{- end }} - namespaceSelector: - matchNames: - - {{ .Release.Namespace }} - selector: - matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} - app.kubernetes.io/component: metrics -{{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/default-backend-configmap.yaml b/deployment/deployment/nginx-ingress-controller/templates/default-backend-configmap.yaml deleted file mode 100644 index cc6bd20..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/default-backend-configmap.yaml +++ /dev/null @@ -1,18 +0,0 @@ -{{- if and (.Values.defaultBackend.enabled) (.Values.defaultBackend.serverBlockConfig) -}} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "nginx-ingress-controller.defaultBackend.fullname" . }} - namespace: {{ .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: default-backend - {{- 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: - defaultBackend.conf: |- - {{- include "common.tplvalues.render" (dict "value" .Values.defaultBackend.serverBlockConfig "context" $) | nindent 4 }} -{{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/default-backend-deployment.yaml b/deployment/deployment/nginx-ingress-controller/templates/default-backend-deployment.yaml deleted file mode 100644 index ffb1c33..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/default-backend-deployment.yaml +++ /dev/null @@ -1,104 +0,0 @@ -{{- if .Values.defaultBackend.enabled }} -apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} -kind: Deployment -metadata: - name: {{ template "nginx-ingress-controller.defaultBackend.fullname" . }} - namespace: {{ .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: default-backend - {{- 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: - selector: - matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} - app.kubernetes.io/component: default-backend - replicas: {{ .Values.defaultBackend.replicaCount }} - template: - metadata: - {{- if .Values.defaultBackend.podAnnotations }} - annotations: {{- include "common.tplvalues.render" (dict "value" .Values.defaultBackend.podAnnotations "context" $) | nindent 8 }} - {{- end }} - labels: {{- include "common.labels.standard" . | nindent 8 }} - app.kubernetes.io/component: default-backend - {{- if .Values.defaultBackend.podLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.defaultBackend.podLabels "context" $) | nindent 8 }} - {{- end }} - spec: - {{- include "nginx-ingress-controller.imagePullSecrets" . | nindent 6 }} - {{- if .Values.defaultBackend.priorityClassName }} - priorityClassName: {{ .Values.defaultBackend.priorityClassName | quote }} - {{- end }} - {{- if .Values.defaultBackend.hostAliases }} - hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.defaultBackend.hostAliases "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.defaultBackend.affinity }} - affinity: {{- include "common.tplvalues.render" ( dict "value" .Values.defaultBackend.affinity "context" $) | nindent 8 }} - {{- else }} - affinity: - podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.defaultBackend.podAffinityPreset "component" "default-backend" "context" $) | nindent 10 }} - podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.defaultBackend.podAntiAffinityPreset "component" "default-backend" "context" $) | nindent 10 }} - nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.defaultBackend.nodeAffinityPreset.type "key" .Values.defaultBackend.nodeAffinityPreset.key "values" .Values.defaultBackend.nodeAffinityPreset.values) | nindent 10 }} - {{- end }} - {{- if .Values.defaultBackend.nodeSelector }} - nodeSelector: {{- include "common.tplvalues.render" ( dict "value" .Values.defaultBackend.nodeSelector "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.defaultBackend.tolerations }} - tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.defaultBackend.tolerations "context" .) | nindent 8 }} - {{- end }} - {{- if .Values.defaultBackend.podSecurityContext.enabled }} - securityContext: {{- omit .Values.defaultBackend.podSecurityContext "enabled" | toYaml | nindent 8 }} - {{- end }} - serviceAccountName: {{ template "nginx-ingress-controller.serviceAccountName" . }} - terminationGracePeriodSeconds: 60 - containers: - - name: default-backend - image: {{ template "nginx-ingress-controller.defaultBackend.image" . }} - imagePullPolicy: {{ .Values.defaultBackend.image.pullPolicy | quote }} - {{- if .Values.defaultBackend.containerSecurityContext.enabled }} - securityContext: {{- omit .Values.defaultBackend.containerSecurityContext "enabled" | toYaml | nindent 12 }} - {{- end }} - args: - {{- range $key, $value := .Values.defaultBackend.extraArgs }} - {{- if $value }} - - --{{ $key }}={{ $value }} - {{- else }} - - --{{ $key }} - {{- end }} - {{- end }} - {{- if .Values.defaultBackend.livenessProbe.enabled }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.defaultBackend.livenessProbe "enabled") "context" $) | nindent 12 }} - {{- else if .Values.defaultBackend.customLivenessProbe }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.defaultBackend.customLivenessProbe "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.defaultBackend.readinessProbe.enabled }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.defaultBackend.readinessProbe "enabled") "context" $) | nindent 12 }} - {{- else if .Values.defaultBackend.customReadinessProbe }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.defaultBackend.customReadinessProbe "context" $) | nindent 12 }} - {{- end }} - ports: - - name: http - containerPort: {{ .Values.defaultBackend.containerPort }} - protocol: TCP - {{- if .Values.defaultBackend.resources }} - resources: {{- toYaml .Values.defaultBackend.resources | nindent 12 }} - {{- end }} - {{- if .Values.defaultBackend.serverBlockConfig }} - volumeMounts: - - name: nginx-config-volume - mountPath: /opt/bitnami/nginx/conf/bitnami/ - readOnly: true - {{- end }} - {{- if .Values.defaultBackend.serverBlockConfig }} - volumes: - - name: nginx-config-volume - configMap: - name: {{ template "nginx-ingress-controller.defaultBackend.fullname" . }} - items: - - key: defaultBackend.conf - path: defaultBackend.conf - {{- end }} -{{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/default-backend-poddisruptionbudget.yaml b/deployment/deployment/nginx-ingress-controller/templates/default-backend-poddisruptionbudget.yaml deleted file mode 100644 index 5271650..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/default-backend-poddisruptionbudget.yaml +++ /dev/null @@ -1,25 +0,0 @@ -{{- if and .Values.defaultBackend.enabled .Values.defaultBackend.pdb.create }} -apiVersion: policy/v1beta1 -kind: PodDisruptionBudget -metadata: - name: {{ include "nginx-ingress-controller.defaultBackend.fullname" . }} - namespace: {{ .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: default-backend - {{- 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.defaultBackend.pdb.minAvailable }} - minAvailable: {{ .Values.defaultBackend.pdb.minAvailable }} - {{- end }} - {{- if .Values.pdb.maxUnavailable }} - maxUnavailable: {{ .Values.defaultBackend.pdb.maxUnavailable }} - {{- end }} - selector: - matchLabels: {{- include "common.labels.matchLabels" . | nindent 4 }} - app.kubernetes.io/component: default-backend -{{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/default-backend-service.yaml b/deployment/deployment/nginx-ingress-controller/templates/default-backend-service.yaml deleted file mode 100644 index a62ab9a..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/default-backend-service.yaml +++ /dev/null @@ -1,30 +0,0 @@ -{{- if .Values.defaultBackend.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: {{ include "nginx-ingress-controller.defaultBackend.fullname" . }} - namespace: {{ .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: default-backend - {{- if .Values.commonLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} - {{- end }} - {{- if or .Values.defaultBackend.service.annotations .Values.commonAnnotations }} - annotations: - {{- if .Values.commonAnnotations }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} - {{- end }} - {{- if .Values.defaultBackend.service.annotations }} - {{- include "common.tplvalues.render" (dict "value" .Values.defaultBackend.service.annotations "context" $) | nindent 4 }} - {{- end }} - {{- end }} -spec: - type: {{ .Values.defaultBackend.service.type }} - ports: - - name: http - port: {{ .Values.defaultBackend.service.port }} - protocol: TCP - targetPort: http - selector: {{- include "common.labels.matchLabels" . | nindent 4 }} - app.kubernetes.io/component: default-backend -{{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/dh-param-secret.yaml b/deployment/deployment/nginx-ingress-controller/templates/dh-param-secret.yaml deleted file mode 100644 index e2fb64e..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/dh-param-secret.yaml +++ /dev/null @@ -1,16 +0,0 @@ -{{- if .Values.dhParam -}} -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "common.names.fullname" . }} - labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: controller - {{- 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: - dhparam.pem: {{ .Values.dhParam | quote }} -{{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/ingressclass.yaml b/deployment/deployment/nginx-ingress-controller/templates/ingressclass.yaml deleted file mode 100644 index d1407e3..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/ingressclass.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- if .Values.ingressClassResource.enabled -}} -apiVersion: networking.k8s.io/v1 -kind: IngressClass -metadata: - labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: controller - {{- if .Values.commonLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} - {{- end }} - name: {{ .Values.ingressClassResource.name }} -{{- if .Values.ingressClassResource.default }} - annotations: - ingressclass.kubernetes.io/is-default-class: "true" -{{- end }} -spec: - controller: {{ .Values.ingressClassResource.controllerClass }} - {{- if .Values.ingressClassResource.parameters }} - parameters: - {{- include "common.tplvalues.render" (dict "value" .Values.ingressClassResource.parameters "context" $) | nindent 4 }} - {{ end }} -{{- end }} \ No newline at end of file diff --git a/deployment/deployment/nginx-ingress-controller/templates/podsecuritypolicy.yaml b/deployment/deployment/nginx-ingress-controller/templates/podsecuritypolicy.yaml deleted file mode 100644 index 316f61e..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/podsecuritypolicy.yaml +++ /dev/null @@ -1,50 +0,0 @@ -{{- $pspAvailable := (semverCompare "<1.25-0" (include "common.capabilities.kubeVersion" .)) -}} -{{- if and $pspAvailable .Values.podSecurityPolicy.enabled}} -apiVersion: policy/v1beta1 -kind: PodSecurityPolicy -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 }} -spec: - allowedCapabilities: - - NET_BIND_SERVICE - privileged: false - allowPrivilegeEscalation: true - volumes: - - 'configMap' - # - 'emptyDir' - # - 'projected' - - 'secret' - # - 'downwardAPI' - hostNetwork: {{ .Values.hostNetwork }} - hostIPC: false - hostPID: false - runAsUser: - # Require the container to run without root privileges. - rule: 'MustRunAsNonRoot' - supplementalGroups: - rule: 'MustRunAs' - ranges: - # Forbid adding the root group. - - min: 1 - max: 65535 - fsGroup: - rule: 'MustRunAs' - ranges: - # Forbid adding the root group. - - min: 1 - max: 65535 - readOnlyRootFilesystem: false - seLinux: - rule: 'RunAsAny' - hostPorts: - - max: 65535 - min: 1 -{{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/proxyheaders-configmap.yaml b/deployment/deployment/nginx-ingress-controller/templates/proxyheaders-configmap.yaml deleted file mode 100644 index 9994dc4..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/proxyheaders-configmap.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- if or .Values.proxySetHeaders .Values.headers }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ printf "%s-custom-proxy-headers" (include "common.names.fullname" .) }} - namespace: {{ .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" . | nindent 4 }} - app.kubernetes.io/component: controller - {{- 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: -{{- if .Values.proxySetHeaders }} -{{- include "common.tplvalues.render" (dict "value" .Values.proxySetHeaders "context" $) | nindent 2 }} -{{- else if and .Values.headers (not .Values.proxySetHeaders) }} -{{- include "common.tplvalues.render" (dict "value" .Values.headers "context" $) | nindent 2 }} -{{- end }} -{{- end }} diff --git a/deployment/deployment/nginx-ingress-controller/templates/role.yaml b/deployment/deployment/nginx-ingress-controller/templates/role.yaml deleted file mode 100644 index 7d27bbe..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/role.yaml +++ /dev/null @@ -1,94 +0,0 @@ -{{- if .Values.rbac.create -}} -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: Role -metadata: - name: {{ template "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: - - namespaces - verbs: - - get - - apiGroups: - - "" - resources: - - configmaps - - pods - - secrets - - endpoints - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - services - verbs: - - get - - list - - update - - watch - - apiGroups: - - extensions - - networking.k8s.io - resources: - - ingresses - verbs: - - get - - list - - watch - - apiGroups: - - extensions - - networking.k8s.io - resources: - - ingresses/status - verbs: - - update - - apiGroups: - - "" - resources: - - configmaps - resourceNames: - - {{ .Values.electionID }} - verbs: - - get - - update - - apiGroups: - - "" - resources: - - configmaps - verbs: - - create - - apiGroups: - - "" - resources: - - endpoints - verbs: - - create - - get - - update - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch - {{- $pspAvailable := (semverCompare "<1.25-0" (include "common.capabilities.kubeVersion" .)) -}} - {{- if and $pspAvailable .Values.podSecurityPolicy.enabled }} - - apiGroups: [{{ template "nginx-ingress-controller.podSecurityPolicy.apiGroup" . }}] - resources: ['podsecuritypolicies'] - verbs: ['use'] - resourceNames: [{{ template "common.names.fullname" . }}] - {{- end }} -{{- end -}} diff --git a/deployment/deployment/nginx-ingress-controller/templates/serviceaccount.yaml b/deployment/deployment/nginx-ingress-controller/templates/serviceaccount.yaml deleted file mode 100644 index 1e177f2..0000000 --- a/deployment/deployment/nginx-ingress-controller/templates/serviceaccount.yaml +++ /dev/null @@ -1,20 +0,0 @@ -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "nginx-ingress-controller.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 }} - {{- if or .Values.serviceAccount.annotations .Values.commonAnnotations }} - annotations: - {{- if .Values.commonAnnotations }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} - {{- end }} - {{- if .Values.serviceAccount.annotations }} - {{- include "common.tplvalues.render" (dict "value" .Values.serviceAccount.annotations "context" $) | nindent 4 }} - {{- end }} - {{- end }} -{{- end -}} diff --git a/deployment/deployment/nginx-ingress-controller/values.yaml b/deployment/deployment/nginx-ingress-controller/values.yaml deleted file mode 100644 index d080698..0000000 --- a/deployment/deployment/nginx-ingress-controller/values.yaml +++ /dev/null @@ -1,815 +0,0 @@ -## @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 -## -global: - imageRegistry: "" - ## E.g. - ## imagePullSecrets: - ## - myRegistryKeySecretName - ## - imagePullSecrets: [] - -## @section Common parameters - -## @param nameOverride String to partially override common.names.fullname -## -nameOverride: "" -## @param fullnameOverride String to fully override common.names.fullname -## -fullnameOverride: "" -## @param commonLabels Add labels to all the deployed resources -## -commonLabels: {} -## @param commonAnnotations Add annotations to all the deployed resources -## -commonAnnotations: {} -## @param extraDeploy Array of extra objects to deploy with the release -## -extraDeploy: [] - -## @section Nginx Ingress Controller parameters - -## Bitnami NGINX Ingress controller image version -## ref: https://hub.docker.com/r/bitnami/nginx-ingress-controller/tags/ -## @param image.registry Nginx Ingress Controller image registry -## @param image.repository Nginx Ingress Controller image repository -## @param image.tag Nginx Ingress Controller image tag (immutable tags are recommended) -## @param image.pullPolicy Nginx Ingress Controller image pull policy -## @param image.pullSecrets Specify docker-registry secret names as an array -## -image: - registry: docker.io - repository: bitnami/nginx-ingress-controller - tag: 1.1.0-debian-10-r0 - ## 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: [] -## @param containerPorts [object] Controller container ports to open -## -containerPorts: - http: 80 - https: 443 - metrics: 10254 -## @param hostAliases Deployment pod host aliases -## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ -## -hostAliases: [] -## @param config Custom configuration options for NGINX -## ref: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/ -## -config: {} -## @param proxySetHeaders Custom headers before sending traffic to backends -## ref: https://github.com/kubernetes/ingress-nginx/tree/master/docs/examples/customization/custom-headers -## -proxySetHeaders: {} -## @param addHeaders Custom headers before sending response traffic to the client -## ref: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#add-headers -## -addHeaders: {} -## @param defaultBackendService Default 404 backend service; required only if `defaultBackend.enabled = false` -## Must be / -## -defaultBackendService: "" -## @param electionID Election ID to use for status update -## -electionID: ingress-controller-leader -## @param reportNodeInternalIp If using `hostNetwork=true`, setting `reportNodeInternalIp=true`, will pass the flag `report-node-internal-ip-address` to Nginx Ingress Controller -## Bare-metal considerations via the host network -## ref: https://kubernetes.github.io/ingress-nginx/deploy/baremetal/#via-the-host-network -## -reportNodeInternalIp: false -## @param watchIngressWithoutClass Process Ingress objects without ingressClass annotation/ingressClassName field -## -watchIngressWithoutClass: false -## Configuring this doesn't affect `kubernetes.io/ingress.class` annotation. See `extraArgs` below how to configure processing of custom annotation. -## @param ingressClassResource.name Name of the IngressClass resource -## @param ingressClassResource.enabled Create the IngressClass resource -## @param ingressClassResource.default Set the created IngressClass resource as default class -## @param ingressClassResource.controllerClass IngressClass identifier for the controller -## @param ingressClassResource.parameters Optional parameters for the controller -## -ingressClassResource: - name: nginx - enabled: true - default: false - controllerClass: "k8s.io/ingress-nginx" - parameters: {} -## Allows customization of the external service -## the ingress will be bound to via DNS -## -publishService: - ## @param publishService.enabled Set the endpoint records on the Ingress objects to reflect those on the service - ## - enabled: false - ## @param publishService.pathOverride Allows overriding of the publish service to bind to - ## Must be / - ## - pathOverride: "" -## @param scope.enabled Limit the scope of the controller. Defaults to `.Release.Namespace` -## -scope: - enabled: false -## @param configMapNamespace Allows customization of the configmap / nginx-configmap namespace -## Defaults to .Release.Namespace -## -configMapNamespace: "" -## @param tcpConfigMapNamespace Allows customization of the tcp-services-configmap namespace -## Defaults to .Release.Namespace -## -tcpConfigMapNamespace: "" -## @param udpConfigMapNamespace Allows customization of the udp-services-configmap namespace -## Defaults to .Release.Namespace -## -udpConfigMapNamespace: "" -## @param maxmindLicenseKey License key used to download Geolite2 database -## -maxmindLicenseKey: "" -## @param dhParam A base64ed Diffie-Hellman parameter -## This can be generated with: openssl dhparam 4096 2> / -## Ref: https://github.com/krmichel/ingress-nginx/blob/master/docs/examples/customization/ssl-dh-param -dhParam: "" -## @param tcp TCP service key:value pairs -## ref: https://github.com/kubernetes/contrib/tree/master/ingress/controllers/nginx/examples/tcp -## e.g: -## tcp: -## 8080: "default/example-tcp-svc:9000" -## -tcp: {} -## @param udp UDP service key:value pairs -## ref: https://github.com/kubernetes/contrib/tree/master/ingress/controllers/nginx/examples/udp -## e.g: -## udp: -## 53: "kube-system/kube-dns:53" -## -udp: {} -## @param command Override default container command (useful when using custom images) -## -command: [] -## @param args Override default container args (useful when using custom images) -## -args: [] -## @param extraArgs Additional command line arguments to pass to nginx-ingress-controller -## E.g. to specify the default SSL certificate you can use -## extraArgs: -## default-ssl-certificate: "/" -## ingress-class: nginx -## -extraArgs: {} -## @param extraEnvVars Extra environment variables to be set on Nginx Ingress container -## E.g: -## extraEnvs: -## - name: FOO -## valueFrom: -## secretKeyRef: -## key: FOO -## name: secret-resource -## -extraEnvVars: [] -## @param extraEnvVarsCM Name of a existing ConfigMap containing extra environment variables -## -extraEnvVarsCM: "" -## @param extraEnvVarsSecret Name of a existing Secret containing extra environment variables -## -extraEnvVarsSecret: "" - -## @section Nginx Ingress deployment / daemonset parameters - -## @param kind Install as Deployment or DaemonSet -## -kind: Deployment -## Daemonset configuration -## -daemonset: - ## @param daemonset.useHostPort If `kind` is `DaemonSet`, this will enable `hostPort` for `TCP/80` and `TCP/443` - ## - useHostPort: false - ## @param daemonset.hostPorts [object] HTTP and HTTPS ports - ## - hostPorts: - http: 80 - https: 443 -## @param replicaCount Desired number of Controller pods -## -replicaCount: 1 -## @param updateStrategy Strategy to use to update Pods -## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies -## -updateStrategy: {} -## @param revisionHistoryLimit The number of old history to retain to allow rollback -## -revisionHistoryLimit: 10 -## Controller pods' Security Context -## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod -## @param podSecurityContext.enabled Enable Controller pods' Security Context -## @param podSecurityContext.fsGroup Group ID for the container filesystem -## -podSecurityContext: - enabled: true - fsGroup: 1001 -## Controller containers' Security Context (only main container) -## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container -## @param containerSecurityContext.enabled Enable Controller containers' Security Context -## @param containerSecurityContext.allowPrivilegeEscalation Switch to allow priviledge escalation on the Controller container -## @param containerSecurityContext.runAsUser User ID for the Controller container -## @param containerSecurityContext.capabilities.drop [array] Linux Kernel capabilities that should be dropped -## @param containerSecurityContext.capabilities.add [array] Linux Kernel capabilities that should be added -## -containerSecurityContext: - enabled: true - allowPrivilegeEscalation: true - runAsUser: 1001 - capabilities: - drop: ["ALL"] - add: ["NET_BIND_SERVICE"] -## @param minReadySeconds How many seconds a pod needs to be ready before killing the next, during update -## -minReadySeconds: 0 -## Controller containers' 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 resources.limits The resources limits for the Controller container -## @param resources.requests The requested resources for the Controller container -## -resources: - ## Example: - ## limits: - ## cpu: 250m - ## memory: 256Mi - limits: {} - ## Examples: - ## requests: - ## cpu: 250m - ## memory: 256Mi - requests: {} -## Controller containers' liveness probe. Evaluated as a template. -## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes -## @param livenessProbe.enabled Enable livenessProbe -## @param livenessProbe.httpGet.path Request path for livenessProbe -## @param livenessProbe.httpGet.port Port for livenessProbe -## @param livenessProbe.httpGet.scheme Scheme for livenessProbe -## @param livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe -## @param livenessProbe.periodSeconds Period seconds for livenessProbe -## @param livenessProbe.timeoutSeconds Timeout seconds for livenessProbe -## @param livenessProbe.failureThreshold Failure threshold for livenessProbe -## @param livenessProbe.successThreshold Success threshold for livenessProbe -## -livenessProbe: - enabled: true - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - failureThreshold: 3 - initialDelaySeconds: 10 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 1 -## Controller containers' readiness probe. Evaluated as a template. -## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes -## @param readinessProbe.enabled Enable readinessProbe -## @param readinessProbe.httpGet.path Request path for readinessProbe -## @param readinessProbe.httpGet.port Port for readinessProbe -## @param readinessProbe.httpGet.scheme Scheme for readinessProbe -## @param readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe -## @param readinessProbe.periodSeconds Period seconds for readinessProbe -## @param readinessProbe.timeoutSeconds Timeout seconds for readinessProbe -## @param readinessProbe.failureThreshold Failure threshold for readinessProbe -## @param readinessProbe.successThreshold Success threshold for readinessProbe -## -readinessProbe: - enabled: true - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - failureThreshold: 3 - initialDelaySeconds: 10 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 1 -## @param customLivenessProbe Override default liveness probe -## -customLivenessProbe: {} -## @param customReadinessProbe Override default readiness probe -## -customReadinessProbe: {} -## @param lifecycle LifecycleHooks to set additional configuration at startup -## -lifecycle: {} -## @param podLabels Extra labels for Controller pods -## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ -## -podLabels: {} -## @param podAnnotations Annotations for Controller pods -## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ -## -podAnnotations: {} -## @param priorityClassName Controller priorityClassName -## ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass -## -priorityClassName: "" -## @param hostNetwork If the Nginx deployment / daemonset should run on the host's network namespace -## Required on CNI based K8s installations, since CNI and hostport don't mix yet -## Can be deprecated once https://github.com/kubernetes/kubernetes/issues/23920 is merged -## -hostNetwork: false -## @param dnsPolicy By default, while using host network, name resolution uses the host's DNS -## Optionally, change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true' if you wish nginx-controller -## to keep resolving names inside the Kubernetes network -## -dnsPolicy: ClusterFirst -## @param terminationGracePeriodSeconds How many seconds to wait before terminating a pod -## -terminationGracePeriodSeconds: 60 -## @param podAffinityPreset Pod affinity preset. Ignored if `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 podAntiAffinityPreset Pod anti-affinity preset. Ignored if `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 -## Node affinity preset -## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity -## -nodeAffinityPreset: - ## @param nodeAffinityPreset.type Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` - ## - type: "" - ## @param nodeAffinityPreset.key Node label key to match. Ignored if `affinity` is set. - ## E.g. - ## key: "kubernetes.io/e2e-az-name" - ## - key: "" - ## @param nodeAffinityPreset.values Node label values to match. Ignored if `affinity` is set. - ## E.g. - ## values: - ## - e2e-az1 - ## - e2e-az2 - ## - values: [] -## @param affinity Affinity for pod assignment. Evaluated as a template. -## 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 nodeSelector Node labels for pod assignment. Evaluated as a template. -## ref: https://kubernetes.io/docs/user-guide/node-selection/ -## -nodeSelector: {} -## @param tolerations Tolerations for pod assignment. Evaluated as a template. -## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ -## -tolerations: [] -## @param extraVolumes Optionally specify extra list of additional volumes for Controller pods -## -extraVolumes: [] -## @param extraVolumeMounts Optionally specify extra list of additional volumeMounts for Controller container(s) -## -extraVolumeMounts: [] -## @param initContainers Add init containers to the controller pods -## Example: -## initContainers: -## - name: your-image-name -## image: your-image -## imagePullPolicy: Always -## ports: -## - name: portname -## containerPort: 1234 -## -initContainers: [] -## @param sidecars Add sidecars to the controller pods. -## Example: -## sidecars: -## - name: your-image-name -## image: your-image -## imagePullPolicy: Always -## ports: -## - name: portname -## containerPort: 1234 -## -sidecars: [] -## @param customTemplate [object] Override NGINX template -## -customTemplate: - configMapName: "" - configMapKey: "" -## @param topologySpreadConstraints Topology spread constraints rely on node labels to identify the topology domain(s) that each Node is in -## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ -## -## topologySpreadConstraints: -## - maxSkew: 1 -## topologyKey: failure-domain.beta.kubernetes.io/zone -## whenUnsatisfiable: DoNotSchedule -## labelSelector: -## matchLabels: -## app.kubernetes.io/instance: ingress-nginx-internal -## -topologySpreadConstraints: [] -## @param podSecurityPolicy.enabled Whether to create a PodSecurityPolicy. WARNING: PodSecurityPolicy is deprecated in Kubernetes v1.21 or later, unavailable in v1.25 or later -## https://kubernetes.io/docs/concepts/policy/pod-security-policy/ -## -podSecurityPolicy: - enabled: false - -## @section Default backend parameters - -## Default 404 backend -## -defaultBackend: - ## @param defaultBackend.enabled Enable a default backend based on NGINX - ## - enabled: true - ## @param defaultBackend.hostAliases Add deployment host aliases - ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ - ## - hostAliases: [] - ## Bitnami NGINX image - ## ref: https://hub.docker.com/r/bitnami/nginx/tags/ - ## @param defaultBackend.image.registry Default backend image registry - ## @param defaultBackend.image.repository Default backend image repository - ## @param defaultBackend.image.tag Default backend image tag (immutable tags are recommended) - ## @param defaultBackend.image.pullPolicy Image pull policy - ## @param defaultBackend.image.pullSecrets Specify docker-registry secret names as an array - ## - image: - registry: docker.io - repository: bitnami/nginx - tag: 1.21.4-debian-10-r19 - ## 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: [] - ## @param defaultBackend.extraArgs Additional command line arguments to pass to Nginx container - ## - extraArgs: {} - ## @param defaultBackend.containerPort HTTP container port number - ## - containerPort: 8080 - ## @param defaultBackend.serverBlockConfig [string] NGINX backend default server block configuration - ## Should be compliant with: https://kubernetes.github.io/ingress-nginx/user-guide/default-backend/ - ## - serverBlockConfig: |- - location /healthz { - return 200; - } - - location / { - return 404; - } - ## @param defaultBackend.replicaCount Desired number of default backend pods - ## - replicaCount: 1 - ## Default backend pods' Security Context - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod - ## @param defaultBackend.podSecurityContext.enabled Enable Default backend pods' Security Context - ## @param defaultBackend.podSecurityContext.fsGroup Group ID for the container filesystem - ## - podSecurityContext: - enabled: true - fsGroup: 1001 - ## Default backend containers' Security Context (only main container) - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container - ## @param defaultBackend.containerSecurityContext.enabled Enable Default backend containers' Security Context - ## @param defaultBackend.containerSecurityContext.runAsUser User ID for the Default backend container - ## - containerSecurityContext: - enabled: true - runAsUser: 1001 - ## Default backend containers' 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 defaultBackend.resources.limits The resources limits for the Default backend container - ## @param defaultBackend.resources.requests The requested resources for the Default backend container - ## - resources: - ## Example: - ## limits: - ## cpu: 250m - ## memory: 256Mi - limits: {} - ## Examples: - ## requests: - ## cpu: 250m - ## memory: 256Mi - requests: {} - ## Default backend containers' liveness probe. Evaluated as a template. - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes - ## @param defaultBackend.livenessProbe.enabled Enable livenessProbe - ## @param defaultBackend.livenessProbe.httpGet.path Request path for livenessProbe - ## @param defaultBackend.livenessProbe.httpGet.port Port for livenessProbe - ## @param defaultBackend.livenessProbe.httpGet.scheme Scheme for livenessProbe - ## @param defaultBackend.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe - ## @param defaultBackend.livenessProbe.periodSeconds Period seconds for livenessProbe - ## @param defaultBackend.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe - ## @param defaultBackend.livenessProbe.failureThreshold Failure threshold for livenessProbe - ## @param defaultBackend.livenessProbe.successThreshold Success threshold for livenessProbe - ## - livenessProbe: - enabled: true - httpGet: - path: /healthz - port: http - scheme: HTTP - failureThreshold: 3 - initialDelaySeconds: 30 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 5 - ## Default backend containers' readiness probe. Evaluated as a template. - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes - ## @param defaultBackend.readinessProbe.enabled Enable readinessProbe - ## @param defaultBackend.readinessProbe.httpGet.path Request path for readinessProbe - ## @param defaultBackend.readinessProbe.httpGet.port Port for readinessProbe - ## @param defaultBackend.readinessProbe.httpGet.scheme Scheme for readinessProbe - ## @param defaultBackend.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe - ## @param defaultBackend.readinessProbe.periodSeconds Period seconds for readinessProbe - ## @param defaultBackend.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe - ## @param defaultBackend.readinessProbe.failureThreshold Failure threshold for readinessProbe - ## @param defaultBackend.readinessProbe.successThreshold Success threshold for readinessProbe - ## - readinessProbe: - enabled: true - httpGet: - path: /healthz - port: http - scheme: HTTP - failureThreshold: 6 - initialDelaySeconds: 0 - periodSeconds: 5 - successThreshold: 1 - timeoutSeconds: 5 - ## @param defaultBackend.podLabels Extra labels for Controller pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ - ## - podLabels: {} - ## @param defaultBackend.podAnnotations Annotations for Controller pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ - ## - podAnnotations: {} - ## @param defaultBackend.priorityClassName priorityClassName - ## ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass - ## - priorityClassName: "" - ## @param defaultBackend.podAffinityPreset Pod affinity preset. Ignored if `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 defaultBackend.podAntiAffinityPreset Pod anti-affinity preset. Ignored if `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 - ## Node affinity preset - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity - ## - nodeAffinityPreset: - ## @param defaultBackend.nodeAffinityPreset.type Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` - ## - type: "" - ## @param defaultBackend.nodeAffinityPreset.key Node label key to match. Ignored if `affinity` is set. - ## E.g. - ## key: "kubernetes.io/e2e-az-name" - ## - key: "" - ## @param defaultBackend.nodeAffinityPreset.values Node label values to match. Ignored if `affinity` is set. - ## E.g. - ## values: - ## - e2e-az1 - ## - e2e-az2 - ## - values: [] - ## @param defaultBackend.affinity Affinity for pod assignment - ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity - ## Note: defaultBackend.podAffinityPreset, defaultBackend.podAntiAffinityPreset, and defaultBackend.nodeAffinityPreset will be ignored when it's set - ## - affinity: {} - ## @param defaultBackend.nodeSelector Node labels for pod assignment - ## ref: https://kubernetes.io/docs/user-guide/node-selection/ - ## - nodeSelector: {} - ## @param defaultBackend.tolerations Tolerations for pod assignment - ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ - ## - tolerations: [] - ## Default backend Service parameters - ## - service: - ## @param defaultBackend.service.type Kubernetes Service type for default backend - ## - type: ClusterIP - ## @param defaultBackend.service.port Default backend service port - ## - port: 80 - ## Default backend Pod Disruption Budget configuration - ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/ - ## - pdb: - ## @param defaultBackend.pdb.create Enable/disable a Pod Disruption Budget creation for Default backend - ## - create: false - ## @param defaultBackend.pdb.minAvailable Minimum number/percentage of Default backend pods that should remain scheduled - ## - minAvailable: 1 - ## @param defaultBackend.pdb.maxUnavailable Maximum number/percentage of Default backend pods that may be made unavailable - ## - maxUnavailable: "" - -## @section Traffic exposure parameters - -## Service parameters -## -service: - ## @param service.type Kubernetes Service type for Controller - ## - type: NodePort - ## @param service.ports [object] Service ports - ## - ports: - http: 80 - https: 443 - ## @param service.targetPorts [object] Map the controller service HTTP/HTTPS port - ## - targetPorts: - http: http - https: https - ## @param service.nodePorts [object] Specify the nodePort value(s) for the LoadBalancer and NodePort service types. - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport - ## - nodePorts: - http: "32032" - https: "31043" - tcp: {} - udp: {} - ## @param service.annotations Annotations for controller service - ## This can be used to set the LoadBalancer service type to internal only. - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer - ## - annotations: {} - ## @param service.labels Labels for controller service - ## - labels: {} - ## @param service.clusterIP Controller Internal Cluster Service IP (optional) - ## - clusterIP: "" - ## @param service.externalIPs Controller Service external IP addresses - ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips - ## - externalIPs: [] - ## @param service.loadBalancerIP Kubernetes LoadBalancerIP to request for Controller (optional, cloud specific) - ## ref: https://kubernetes.io/docs/user-guide/services/#type-loadbalancer - ## - loadBalancerIP: "" - ## @param service.loadBalancerSourceRanges List of IP CIDRs allowed access to load balancer (if supported) - ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service - ## - loadBalancerSourceRanges: [] - ## @param service.externalTrafficPolicy Set external traffic policy to: "Local" to preserve source IP on providers supporting it - ## Enable client source IP preservation - ## Ref: https://kubernetes.io/docs/tutorials/services/source-ip/#source-ip-for-services-with-typeloadbalancer - ## - externalTrafficPolicy: "" - ## @param service.healthCheckNodePort Set this to the managed health-check port the kube-proxy will expose. If blank, a random port in the `NodePort` range will be assigned - ## - healthCheckNodePort: 0 - -## @section RBAC parameters - -## Pods Service Account -## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ -## -serviceAccount: - ## @param serviceAccount.create Enable the creation of a ServiceAccount for Controller pods - ## - create: true - ## @param serviceAccount.name Name of the created ServiceAccount - ## If not set and create is true, a name is generated using the metrics-server.fullname template - name: "" - ## @param serviceAccount.annotations Annotations for service account. - ## Only used if `create` is `true`. - ## - annotations: {} -## Role Based Access -## Ref: https://kubernetes.io/docs/admin/authorization/rbac/ -## -rbac: - ## @param rbac.create Specifies whether RBAC rules should be created - ## - create: true - -## @section Other parameters - -## Controller Pod Disruption Budget configuration -## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/ -## -pdb: - ## @param pdb.create Enable/disable a Pod Disruption Budget creation for Controller - ## - create: false - ## @param pdb.minAvailable Minimum number/percentage of Controller pods that should remain scheduled - ## - minAvailable: 1 - ## @param pdb.maxUnavailable Maximum number/percentage of Controller pods that may be made unavailable - ## - maxUnavailable: "" -## Controller Autoscaling configuration -## @param autoscaling.enabled Enable autoscaling for Controller -## @param autoscaling.minReplicas Minimum number of Controller replicas -## @param autoscaling.maxReplicas Maximum number of Controller replicas -## @param autoscaling.targetCPU Target CPU utilization percentage -## @param autoscaling.targetMemory Target Memory utilization percentage -## -autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 11 - targetCPU: "" - targetMemory: "" - -## @section Metrics parameters - -## Prometheus exporter parameters -## -metrics: - ## @param metrics.enabled Enable exposing Controller statistics - ## - enabled: false - ## Prometheus exporter service parameters - ## - service: - ## @param metrics.service.type Type of Prometheus metrics service to create - ## - type: ClusterIP - ## @param metrics.service.port Service HTTP management port - ## - port: 9913 - ## @param metrics.service.annotations [object] Annotations for the Prometheus exporter service - ## - annotations: - prometheus.io/scrape: "true" - prometheus.io/port: "{{ .Values.metrics.service.port }}" - ## Prometheus Operator ServiceMonitor configuration - ## - serviceMonitor: - ## @param metrics.serviceMonitor.enabled Create ServiceMonitor resource for scraping metrics using PrometheusOperator - ## - enabled: false - ## @param metrics.serviceMonitor.namespace Namespace in which Prometheus is running - ## - namespace: "" - ## @param metrics.serviceMonitor.interval Interval at which metrics should be scraped - ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#endpoint - ## - interval: 30s - ## @param metrics.serviceMonitor.scrapeTimeout Specify the timeout after which the scrape is ended - ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#endpoint - ## e.g: - ## scrapeTimeout: 10s - ## - scrapeTimeout: "" - ## @param metrics.serviceMonitor.selector ServiceMonitor selector labels - ## ref: https://github.com/bitnami/charts/tree/master/bitnami/prometheus-operator#prometheus-configuration - ## e.g: - ## selector: - ## prometheus: my-prometheus - ## - selector: {} - ## @param metrics.prometheusRule.enabled Create PrometheusRules resource for scraping metrics using PrometheusOperator - ## @param metrics.prometheusRule.additionalLabels Used to pass Labels that are required by the Installed Prometheus Operator - ## @param metrics.prometheusRule.namespace Namespace which Prometheus is running in - ## @param metrics.prometheusRule.rules Rules to be prometheus in YAML format, check values for an example - ## - prometheusRule: - enabled: false - additionalLabels: {} - namespace: "" - rules: [] diff --git a/deployment/deployment/portalauth/Chart.yaml b/deployment/deployment/portalauth/Chart.yaml deleted file mode 100644 index 647ea8f..0000000 --- a/deployment/deployment/portalauth/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: audit -version: 0.1.0 diff --git a/deployment/deployment/portalauth/templates/job.yaml b/deployment/deployment/portalauth/templates/job.yaml deleted file mode 100644 index 00d6959..0000000 --- a/deployment/deployment/portalauth/templates/job.yaml +++ /dev/null @@ -1,34 +0,0 @@ -kind: Job -apiVersion: batch/v1 -metadata: - name: auth-job - namespace: {{ .Values.namespace }} - labels: - app: auth-job -spec: - parallelism: 1 - completions: 1 - activeDeadlineSeconds: 3600 - backoffLimit: 1 - template: - metadata: - labels: - app: auth-job - job-name: auth-job - spec: - containers: - - name: container-o55dxy - image: '{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }}' - resources: {} - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - imagePullPolicy: Always - restartPolicy: Never - terminationGracePeriodSeconds: 30 - dnsPolicy: ClusterFirst - serviceAccountName: default - serviceAccount: default - securityContext: {} - imagePullSecrets: - - name: {{ .Values.imagePullSecrets }} - schedulerName: default-scheduler \ No newline at end of file diff --git a/deployment/deployment/portalauth/values.yaml b/deployment/deployment/portalauth/values.yaml deleted file mode 100644 index bd00c29..0000000 --- a/deployment/deployment/portalauth/values.yaml +++ /dev/null @@ -1,6 +0,0 @@ -image: - name: setauth - repo: docker.io/quanxiang - tag: v1.1.2_nofaas -namespace: "" -imagePullSecrets: qxcr diff --git a/deployment/deployment/quanxiang_charts/app-center/Chart.yaml b/deployment/deployment/quanxiang_charts/app-center/Chart.yaml deleted file mode 100644 index bda1423..0000000 --- a/deployment/deployment/quanxiang_charts/app-center/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: app-center -version: 0.1.0 diff --git a/deployment/deployment/quanxiang_charts/app-center/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/app-center/templates/NOTES.txt deleted file mode 100644 index d88e9ed..0000000 --- a/deployment/deployment/quanxiang_charts/app-center/templates/NOTES.txt +++ /dev/null @@ -1,21 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "app-center.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 }} - 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 "app-center.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "app-center.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "app-center.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 port-forward $POD_NAME 8080:80 -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/app-center/values.yaml b/deployment/deployment/quanxiang_charts/app-center/values.yaml deleted file mode 100644 index 2b5087c..0000000 --- a/deployment/deployment/quanxiang_charts/app-center/values.yaml +++ /dev/null @@ -1,93 +0,0 @@ -image: - name: appcenter - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: app_center - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: - - host: lowcode.quanxiangyun.com - paths: - - fullName: app-center - path: / - svcPort: 80 -app: - kubernetes: - io: - name: backend diff --git a/deployment/deployment/quanxiang_charts/audit/Chart.yaml b/deployment/deployment/quanxiang_charts/audit/Chart.yaml deleted file mode 100644 index 647ea8f..0000000 --- a/deployment/deployment/quanxiang_charts/audit/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: audit -version: 0.1.0 diff --git a/deployment/deployment/quanxiang_charts/audit/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/audit/templates/NOTES.txt deleted file mode 100644 index 41faec5..0000000 --- a/deployment/deployment/quanxiang_charts/audit/templates/NOTES.txt +++ /dev/null @@ -1,21 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "audit.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 }} - 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 "audit.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "audit.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "audit.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 port-forward $POD_NAME 8080:80 -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/audit/values.yaml b/deployment/deployment/quanxiang_charts/audit/values.yaml deleted file mode 100644 index dbfb5a0..0000000 --- a/deployment/deployment/quanxiang_charts/audit/values.yaml +++ /dev/null @@ -1,90 +0,0 @@ -image: - name: audit - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: "" - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: - - host: chart-example.local - paths: [] -app: - kubernetes: - io: - name: backend diff --git a/deployment/deployment/quanxiang_charts/builder/templates/serviceaccount.yaml b/deployment/deployment/quanxiang_charts/builder/templates/serviceaccount.yaml deleted file mode 100644 index 51c4a22..0000000 --- a/deployment/deployment/quanxiang_charts/builder/templates/serviceaccount.yaml +++ /dev/null @@ -1,19 +0,0 @@ -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "builder.serviceAccountName" . }} - labels: - {{- include "builder.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -secrets: - {{- with .Values.dockerConfig }} - - name: {{ .name }} - {{- end }} - {{- with .Values.gitSSH }} - - name: {{ .name }} - {{- end }} -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/builder/values.yaml b/deployment/deployment/quanxiang_charts/builder/values.yaml deleted file mode 100644 index 111eab6..0000000 --- a/deployment/deployment/quanxiang_charts/builder/values.yaml +++ /dev/null @@ -1,54 +0,0 @@ -image: - name: "" - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -lowcode: lowcode -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: "" - port: 0 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - create: true - name: builder -podSecurityContext: {} -securityContext: {} -dockerConfig: - name: faas-docker - data: - -gitSSH: - name: rsa - annotations: - tekton.dev/git-0: - ssh_privatekey: - known_hosts: - -ingress: - enabled: false - hosts: [] -app: - kubernetes: - io: - name: "" diff --git a/deployment/deployment/quanxiang_charts/dispatcher/Chart.yaml b/deployment/deployment/quanxiang_charts/dispatcher/Chart.yaml deleted file mode 100644 index 878edca..0000000 --- a/deployment/deployment/quanxiang_charts/dispatcher/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: dispatcher -version: 0.1.0 diff --git a/deployment/deployment/quanxiang_charts/dispatcher/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/dispatcher/templates/NOTES.txt deleted file mode 100644 index 7199a6d..0000000 --- a/deployment/deployment/quanxiang_charts/dispatcher/templates/NOTES.txt +++ /dev/null @@ -1,21 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "dispatcher.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 }} - 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 "dispatcher.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "dispatcher.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "dispatcher.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") - echo "Visit http://127.0.0.1:80 to use your application" - kubectl port-forward $POD_NAME 80:80 -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/dispatcher/values.yaml b/deployment/deployment/quanxiang_charts/dispatcher/values.yaml deleted file mode 100644 index 67dff4d..0000000 --- a/deployment/deployment/quanxiang_charts/dispatcher/values.yaml +++ /dev/null @@ -1,93 +0,0 @@ -image: - name: dispatcher - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: dispatcher - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: - - host: lowcode.quanxiangyun.com - paths: - - fullName: dispatcher - path: / - svcPort: 80 -app: - kubernetes: - io: - name: backend diff --git a/deployment/deployment/quanxiang_charts/entrepot/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/entrepot/templates/NOTES.txt deleted file mode 100644 index 981091c..0000000 --- a/deployment/deployment/quanxiang_charts/entrepot/templates/NOTES.txt +++ /dev/null @@ -1,22 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- 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 }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "entrepot.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 }} - 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 "entrepot.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "entrepot.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "entrepot.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") - export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") - echo "Visit http://127.0.0.1:8080 to use your application" - kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/entrepot/templates/tests/test-connection.yaml b/deployment/deployment/quanxiang_charts/entrepot/templates/tests/test-connection.yaml deleted file mode 100644 index 12028d5..0000000 --- a/deployment/deployment/quanxiang_charts/entrepot/templates/tests/test-connection.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: "{{ include "entrepot.fullname" . }}-test-connection" - labels: - {{- include "entrepot.labels" . | nindent 4 }} - annotations: - "helm.sh/hook": test -spec: - containers: - - name: wget - image: busybox - command: ['wget'] - args: ['{{ include "entrepot.fullname" . }}:{{ .Values.service.port }}'] - restartPolicy: Never diff --git a/deployment/deployment/quanxiang_charts/entrepot/values.yaml b/deployment/deployment/quanxiang_charts/entrepot/values.yaml deleted file mode 100644 index 443c19e..0000000 --- a/deployment/deployment/quanxiang_charts/entrepot/values.yaml +++ /dev/null @@ -1,93 +0,0 @@ -image: - name: entrepot - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: entrepot - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: - - host: lowcode.quanxiangyun.com - paths: - - fullName: app-center - path: / - svcPort: 80 -app: - kubernetes: - io: - name: lowcode diff --git a/deployment/deployment/quanxiang_charts/faas/values.yaml b/deployment/deployment/quanxiang_charts/faas/values.yaml deleted file mode 100644 index b9ce392..0000000 --- a/deployment/deployment/quanxiang_charts/faas/values.yaml +++ /dev/null @@ -1,90 +0,0 @@ -image: - name: faas - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -code: - import: github.com/quanxiang-cloud/faas-lowcode-interface/lowcode -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: dispatcher - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: [] -app: - kubernetes: - io: - name: lowcode diff --git a/deployment/deployment/quanxiang_charts/fileserver/Chart.yaml b/deployment/deployment/quanxiang_charts/fileserver/Chart.yaml deleted file mode 100644 index 19ebf01..0000000 --- a/deployment/deployment/quanxiang_charts/fileserver/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: fileserver -version: 0.1.0 diff --git a/deployment/deployment/quanxiang_charts/fileserver/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/fileserver/templates/NOTES.txt deleted file mode 100644 index 78c54ae..0000000 --- a/deployment/deployment/quanxiang_charts/fileserver/templates/NOTES.txt +++ /dev/null @@ -1,21 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "oauth2c.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 }} - 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 "oauth2c.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "oauth2c.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "oauth2c.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 port-forward $POD_NAME 8080:80 -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/fileserver/values.yaml b/deployment/deployment/quanxiang_charts/fileserver/values.yaml deleted file mode 100644 index 22a713f..0000000 --- a/deployment/deployment/quanxiang_charts/fileserver/values.yaml +++ /dev/null @@ -1,93 +0,0 @@ -image: - name: fileserver - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: fileserver - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: - - host: '*.fs.example.com' - paths: - - fullName: minio - path: / - svcPort: 9000 -app: - kubernetes: - io: - name: backend diff --git a/deployment/deployment/quanxiang_charts/flow/Chart.yaml b/deployment/deployment/quanxiang_charts/flow/Chart.yaml deleted file mode 100644 index 5455713..0000000 --- a/deployment/deployment/quanxiang_charts/flow/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: flow -version: 0.1.0 diff --git a/deployment/deployment/quanxiang_charts/flow/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/flow/templates/NOTES.txt deleted file mode 100644 index 9704fb0..0000000 --- a/deployment/deployment/quanxiang_charts/flow/templates/NOTES.txt +++ /dev/null @@ -1,21 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "flow.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 }} - 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 "flow.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "flow.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "flow.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 port-forward $POD_NAME 8080:80 -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/flow/values.yaml b/deployment/deployment/quanxiang_charts/flow/values.yaml deleted file mode 100644 index b1889fa..0000000 --- a/deployment/deployment/quanxiang_charts/flow/values.yaml +++ /dev/null @@ -1,93 +0,0 @@ -image: - name: flow - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379,redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379,redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - password: qxp1234 -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 9081 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: flow - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: - - host: lowcode.quanxiangyun.com - paths: - - fullName: flow - path: / - svcPort: 80 -app: - kubernetes: - io: - name: backend diff --git a/deployment/deployment/quanxiang_charts/fluent-bit/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/fluent-bit/templates/NOTES.txt deleted file mode 100755 index bbfcc0b..0000000 --- a/deployment/deployment/quanxiang_charts/fluent-bit/templates/NOTES.txt +++ /dev/null @@ -1,15 +0,0 @@ -fluent-bit is now running. - -{{- if eq .Values.backend.type "forward" }} - -It will forward all container logs to the svc named {{ .Values.backend.forward.host }} on port: {{ .Values.backend.forward.port }} -{{- else if eq .Values.backend.type "es" }} - -It will forward all container logs to the svc named {{ .Values.backend.es.host }} on port: {{ .Values.backend.es.port }} -{{- else if eq .Values.backend.type "http" }} - -It will forward all container logs to the svc named {{ .Values.backend.http.host }} on port: {{ .Values.backend.http.port }} -{{- else if eq .Values.backend.type "splunk" }} - -It will forward all container logs to the svc named {{ .Values.backend.splunk.host }} on port: {{ .Values.backend.splunk.port }} -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/form/Chart.yaml b/deployment/deployment/quanxiang_charts/form/Chart.yaml deleted file mode 100644 index d832d2c..0000000 --- a/deployment/deployment/quanxiang_charts/form/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: form -version: 0.1.0 diff --git a/deployment/deployment/quanxiang_charts/form/pub_sub_redis.yaml_bak b/deployment/deployment/quanxiang_charts/form/pub_sub_redis.yaml_bak deleted file mode 100644 index 26bfc90..0000000 --- a/deployment/deployment/quanxiang_charts/form/pub_sub_redis.yaml_bak +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: dapr.io/v1alpha1 -kind: Component -metadata: - name: form-pubsub -spec: - type: pubsub.redis - version: v1 - metadata: - - name: redisType - value: "cluster" - - name: redisHost - value: {{ .Values.redis.host}} - - name: redisPassword - value: {{ .Values.redis.password}} - - name: maxMessageBytes - value: 1024 diff --git a/deployment/deployment/quanxiang_charts/form/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/form/templates/NOTES.txt deleted file mode 100644 index 4e99def..0000000 --- a/deployment/deployment/quanxiang_charts/form/templates/NOTES.txt +++ /dev/null @@ -1,21 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "form.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 }} - 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 "form.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "form.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "form.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 port-forward $POD_NAME 8080:80 -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/form/values.yaml b/deployment/deployment/quanxiang_charts/form/values.yaml deleted file mode 100644 index 3cb360c..0000000 --- a/deployment/deployment/quanxiang_charts/form/values.yaml +++ /dev/null @@ -1,93 +0,0 @@ -image: - name: form - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: mongodb.{{.}}.svc.cluster.local:27017 -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 8080 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: "" - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: - - host: lowcode.quanxiangyun.com - paths: - - fullName: form - path: / - svcPort: 80 -app: - kubernetes: - io: - name: backend diff --git a/deployment/deployment/quanxiang_charts/goalie/Chart.yaml b/deployment/deployment/quanxiang_charts/goalie/Chart.yaml deleted file mode 100644 index 3634bf4..0000000 --- a/deployment/deployment/quanxiang_charts/goalie/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: goalie -version: 0.1.0 diff --git a/deployment/deployment/quanxiang_charts/goalie/values.yaml b/deployment/deployment/quanxiang_charts/goalie/values.yaml deleted file mode 100644 index 4214fd7..0000000 --- a/deployment/deployment/quanxiang_charts/goalie/values.yaml +++ /dev/null @@ -1,88 +0,0 @@ -image: - name: goalie - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: goalie - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: [] -app: - kubernetes: - io: - name: backend diff --git a/deployment/deployment/quanxiang_charts/implant/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/implant/templates/NOTES.txt deleted file mode 100644 index a5a049b..0000000 --- a/deployment/deployment/quanxiang_charts/implant/templates/NOTES.txt +++ /dev/null @@ -1,22 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- 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 }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "implant.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 }} - 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 "implant.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "implant.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "implant.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") - export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") - echo "Visit http://127.0.0.1:8080 to use your application" - kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/implant/values.yaml b/deployment/deployment/quanxiang_charts/implant/values.yaml deleted file mode 100644 index 80fc82d..0000000 --- a/deployment/deployment/quanxiang_charts/implant/values.yaml +++ /dev/null @@ -1,140 +0,0 @@ -# Default values for implant. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -replicaCount: 1 - -image: - name: implant - repo: wentevill - tag: alpha1 - pullPolicy: IfNotPresent - # Overrides the image tag whose default is the chart appVersion. - -namespace: "" -imagePullSecrets: "" -nameOverride: "" -fullnameOverride: "" - -serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - -podAnnotations: {} - -podSecurityContext: {} - # fsGroup: 2000 - -securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 - -service: - type: ClusterIP - port: 80 -config: - jwtKey: "" - mysql: - db: polyapi - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - className: "" - annotations: {} - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: "true" - hosts: - - host: chart-example.local - paths: - - path: / - pathType: ImplementationSpecific - tls: [] - # - secretName: chart-example-tls - # hosts: - # - chart-example.local - -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:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi - -autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 100 - targetCPUUtilizationPercentage: 80 - # targetMemoryUtilizationPercentage: 80 - -nodeSelector: {} - -clusterRole: - create: true - name: implant - annotations: - rbac.authorization.kubernetes.io/autoupdate: "true" - -tolerations: [] - -affinity: {} -app: - kubernetes: - io: - name: lowcode \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/kms/Chart.yaml b/deployment/deployment/quanxiang_charts/kms/Chart.yaml deleted file mode 100644 index 6ef9e86..0000000 --- a/deployment/deployment/quanxiang_charts/kms/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: kms -version: 0.1.0 diff --git a/deployment/deployment/quanxiang_charts/kms/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/kms/templates/NOTES.txt deleted file mode 100644 index a9f56db..0000000 --- a/deployment/deployment/quanxiang_charts/kms/templates/NOTES.txt +++ /dev/null @@ -1,21 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "keeper.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 }} - 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 "keeper.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "keeper.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "keeper.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 port-forward $POD_NAME 8080:80 -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/kms/values.yaml b/deployment/deployment/quanxiang_charts/kms/values.yaml deleted file mode 100644 index 270042a..0000000 --- a/deployment/deployment/quanxiang_charts/kms/values.yaml +++ /dev/null @@ -1,88 +0,0 @@ -image: - name: kms - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: kms - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: [] -app: - kubernetes: - io: - name: backend diff --git a/deployment/deployment/quanxiang_charts/message/Chart.yaml b/deployment/deployment/quanxiang_charts/message/Chart.yaml deleted file mode 100644 index aa43923..0000000 --- a/deployment/deployment/quanxiang_charts/message/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "0.7.0" -description: A Helm chart for Kubernetes -name: audit -version: 0.7.0 diff --git a/deployment/deployment/quanxiang_charts/message/values.yaml b/deployment/deployment/quanxiang_charts/message/values.yaml deleted file mode 100644 index edab366..0000000 --- a/deployment/deployment/quanxiang_charts/message/values.yaml +++ /dev/null @@ -1,96 +0,0 @@ -image: - name: "" - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: message - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - - 192.168.201.21:27017 - - 192.168.201.22:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - enabled: true - host: xx.xx.xx - port: 465 - username: xx - password: xx - alias: xx - sender: xx@.com -ingress: - enabled: false - hosts: [] -app: - kubernetes: - io: - name: lowcode diff --git a/deployment/deployment/quanxiang_charts/organizations/Chart.yaml b/deployment/deployment/quanxiang_charts/organizations/Chart.yaml deleted file mode 100644 index cafb512..0000000 --- a/deployment/deployment/quanxiang_charts/organizations/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: organizations -version: 0.1.0 diff --git a/deployment/deployment/quanxiang_charts/organizations/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/organizations/templates/NOTES.txt deleted file mode 100644 index 7ac44d1..0000000 --- a/deployment/deployment/quanxiang_charts/organizations/templates/NOTES.txt +++ /dev/null @@ -1,21 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "organizations.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 }} - 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 "organizations.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "organizations.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "organizations.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 port-forward $POD_NAME 8080:80 -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/organizations/templates/ingress.yaml b/deployment/deployment/quanxiang_charts/organizations/templates/ingress.yaml deleted file mode 100644 index 5190f01..0000000 --- a/deployment/deployment/quanxiang_charts/organizations/templates/ingress.yaml +++ /dev/null @@ -1,41 +0,0 @@ -{{- if .Values.ingress.enabled -}} -{{- $fullName := include "organizations.fullname" . -}} -{{- $svcPort := .Values.service.port -}} -{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} -apiVersion: networking.k8s.io/v1 -{{- else -}} -apiVersion: extensions/v1beta1 -{{- end }} -kind: Ingress -metadata: - name: {{ $fullName }} - labels: -{{ include "organizations.labels" . | indent 4 }} - {{- with .Values.ingress.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: -{{- if .Values.ingress.tls }} - tls: - {{- range .Values.ingress.tls }} - - hosts: - {{- range .hosts }} - - {{ . | quote }} - {{- end }} - secretName: {{ .secretName }} - {{- end }} -{{- end }} - rules: - {{- range .Values.ingress.hosts }} - - host: {{ .host | quote }} - http: - paths: - {{- range .paths }} - - path: {{ . }} - backend: - serviceName: {{ $fullName }} - servicePort: {{ $svcPort }} - {{- end }} - {{- end }} -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/organizations/values.yaml b/deployment/deployment/quanxiang_charts/organizations/values.yaml deleted file mode 100644 index a1f0050..0000000 --- a/deployment/deployment/quanxiang_charts/organizations/values.yaml +++ /dev/null @@ -1,88 +0,0 @@ -image: - name: organizations - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: organizations - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: [] -app: - kubernetes: - io: - name: backend diff --git a/deployment/deployment/quanxiang_charts/persona/Chart.yaml b/deployment/deployment/quanxiang_charts/persona/Chart.yaml deleted file mode 100644 index 8062635..0000000 --- a/deployment/deployment/quanxiang_charts/persona/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: persona -version: 0.1.0 diff --git a/deployment/deployment/quanxiang_charts/persona/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/persona/templates/NOTES.txt deleted file mode 100644 index 8596670..0000000 --- a/deployment/deployment/quanxiang_charts/persona/templates/NOTES.txt +++ /dev/null @@ -1,21 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "persona.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 }} - 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 "persona.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "persona.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "persona.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") - echo "Visit http://127.0.0.1:80 to use your application" - kubectl port-forward $POD_NAME 80:80 -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/persona/values.yaml b/deployment/deployment/quanxiang_charts/persona/values.yaml deleted file mode 100644 index c63c18c..0000000 --- a/deployment/deployment/quanxiang_charts/persona/values.yaml +++ /dev/null @@ -1,97 +0,0 @@ -image: - name: persona - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: "" - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - - "" - - "" - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - - 192.168.201.21:27017 - - 192.168.201.22:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: - - host: lowcode.quanxiangyun.com - paths: - - fullName: persona - path: / - svcPort: 80 -app: - kubernetes: - io: - name: lowcode diff --git a/deployment/deployment/quanxiang_charts/polyapi/Chart.yaml b/deployment/deployment/quanxiang_charts/polyapi/Chart.yaml deleted file mode 100644 index d7eb8d6..0000000 --- a/deployment/deployment/quanxiang_charts/polyapi/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: polyapi -version: 0.1.0 diff --git a/deployment/deployment/quanxiang_charts/polyapi/templates/de.bak b/deployment/deployment/quanxiang_charts/polyapi/templates/de.bak deleted file mode 100644 index 0f37fff..0000000 --- a/deployment/deployment/quanxiang_charts/polyapi/templates/de.bak +++ /dev/null @@ -1,51 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: low-code - labels: - version: v1 - app: polyapi - name: polyapi-v1 -spec: - replicas: 1 - selector: - matchLabels: - version: v1 - app: polyapi - template: - metadata: - labels: - version: v1 - app: polyapi - annotations: - kubesphere.io/containerSecrets: '{"container-kudq8k":"docker"}' - logging.kubesphere.io/logsidecar-config: '{}' - spec: - containers: - - name: container-kudq8k - imagePullPolicy: IfNotPresent - image: 'dockerhub.qingcloud.com/lowcode/polyapi:{{ .Values.image.tag }}' - ports: - - name: tcp-80 - protocol: TCP - containerPort: 80 - servicePort: 80 - volumeMounts: - - name: volume-yl0ncd - readOnly: true - mountPath: configs - serviceAccount: default - affinity: {} - initContainers: [] - volumes: - - name: volume-yl0ncd - configMap: - name: polyapi - imagePullSecrets: - - name: docker - strategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 25% - maxSurge: 25% - diff --git a/deployment/deployment/quanxiang_charts/polyapi/values.yaml b/deployment/deployment/quanxiang_charts/polyapi/values.yaml deleted file mode 100644 index a0a7905..0000000 --- a/deployment/deployment/quanxiang_charts/polyapi/values.yaml +++ /dev/null @@ -1,93 +0,0 @@ -image: - name: polyapi - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 9090 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: polyapi - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: true - hosts: - - host: polyapi.example.com - paths: - - fullName: polyapi - path: / - svcPort: 80 -app: - kubernetes: - io: - name: backend diff --git a/deployment/deployment/quanxiang_charts/polygate/Chart.yaml b/deployment/deployment/quanxiang_charts/polygate/Chart.yaml deleted file mode 100644 index f762db4..0000000 --- a/deployment/deployment/quanxiang_charts/polygate/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "0.7.0" -description: A Helm chart for Kubernetes -name: polyapi -version: 0.7.0 diff --git a/deployment/deployment/quanxiang_charts/polygate/templates/de.bak b/deployment/deployment/quanxiang_charts/polygate/templates/de.bak deleted file mode 100644 index 0f37fff..0000000 --- a/deployment/deployment/quanxiang_charts/polygate/templates/de.bak +++ /dev/null @@ -1,51 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: low-code - labels: - version: v1 - app: polyapi - name: polyapi-v1 -spec: - replicas: 1 - selector: - matchLabels: - version: v1 - app: polyapi - template: - metadata: - labels: - version: v1 - app: polyapi - annotations: - kubesphere.io/containerSecrets: '{"container-kudq8k":"docker"}' - logging.kubesphere.io/logsidecar-config: '{}' - spec: - containers: - - name: container-kudq8k - imagePullPolicy: IfNotPresent - image: 'dockerhub.qingcloud.com/lowcode/polyapi:{{ .Values.image.tag }}' - ports: - - name: tcp-80 - protocol: TCP - containerPort: 80 - servicePort: 80 - volumeMounts: - - name: volume-yl0ncd - readOnly: true - mountPath: configs - serviceAccount: default - affinity: {} - initContainers: [] - volumes: - - name: volume-yl0ncd - configMap: - name: polyapi - imagePullSecrets: - - name: docker - strategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 25% - maxSurge: 25% - diff --git a/deployment/deployment/quanxiang_charts/polygate/values.yaml b/deployment/deployment/quanxiang_charts/polygate/values.yaml deleted file mode 100644 index abe4a54..0000000 --- a/deployment/deployment/quanxiang_charts/polygate/values.yaml +++ /dev/null @@ -1,102 +0,0 @@ -image: - name: polygate - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 9090 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: "" - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - - "" - - "" - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - - 192.168.201.21:27017 - - 192.168.201.22:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: true - hosts: - - host: ws.example.com - paths: - - fullName: message - path: / - svcPort: 8080 - - host: api.example.com - paths: - - fullName: polygate - path: / - svcPort: 80 -app: - kubernetes: - io: - name: lowcode diff --git a/deployment/deployment/quanxiang_charts/process/Chart.yaml b/deployment/deployment/quanxiang_charts/process/Chart.yaml deleted file mode 100644 index d6637cc..0000000 --- a/deployment/deployment/quanxiang_charts/process/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: process -version: 0.1.0 diff --git a/deployment/deployment/quanxiang_charts/process/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/process/templates/NOTES.txt deleted file mode 100644 index 3606545..0000000 --- a/deployment/deployment/quanxiang_charts/process/templates/NOTES.txt +++ /dev/null @@ -1,21 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "process.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 }} - 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 "process.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "process.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "process.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 port-forward $POD_NAME 8080:80 -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/process/values.yaml b/deployment/deployment/quanxiang_charts/process/values.yaml deleted file mode 100644 index 225d793..0000000 --- a/deployment/deployment/quanxiang_charts/process/values.yaml +++ /dev/null @@ -1,93 +0,0 @@ -image: - name: process - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: process - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: - - host: lowcode.quanxiangyun.com - paths: - - fullName: process - path: / - svcPort: 80 -app: - kubernetes: - io: - name: backend diff --git a/deployment/deployment/quanxiang_charts/qxp-web-home/Chart.yaml b/deployment/deployment/quanxiang_charts/qxp-web-home/Chart.yaml deleted file mode 100644 index d3128f0..0000000 --- a/deployment/deployment/quanxiang_charts/qxp-web-home/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: qxp-web-home -version: 0.1.0 diff --git a/deployment/deployment/quanxiang_charts/qxp-web-home/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/qxp-web-home/templates/NOTES.txt deleted file mode 100644 index 41faec5..0000000 --- a/deployment/deployment/quanxiang_charts/qxp-web-home/templates/NOTES.txt +++ /dev/null @@ -1,21 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "audit.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 }} - 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 "audit.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "audit.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "audit.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 port-forward $POD_NAME 8080:80 -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/qxp-web-home/templates/ingress.yml b/deployment/deployment/quanxiang_charts/qxp-web-home/templates/ingress.yml deleted file mode 100644 index 08fad3b..0000000 --- a/deployment/deployment/quanxiang_charts/qxp-web-home/templates/ingress.yml +++ /dev/null @@ -1,26 +0,0 @@ -kind: Ingress -apiVersion: networking.k8s.io/v1 -metadata: - name: qxp-home - namespace: {{ .Values.namespace }} - annotations: - kubernetes.io/ingress.class: nginx - nginx.ingress.kubernetes.io/proxy-body-size: 30m - labels: - app.kubernetes.io/version: v1 -spec: - rules: - {{- range .Values.ingress.hosts }} - - host: {{ .host | quote }} - http: - paths: - {{- range .paths }} - - path: {{ .path }} - pathType: Prefix - backend: - service: - name: {{ .fullName }} - port: - number: {{ .svcPort }} - {{- end }} - {{- end }} \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/qxp-web-home/values.yaml b/deployment/deployment/quanxiang_charts/qxp-web-home/values.yaml deleted file mode 100644 index 7729773..0000000 --- a/deployment/deployment/quanxiang_charts/qxp-web-home/values.yaml +++ /dev/null @@ -1,103 +0,0 @@ -image: - name: qxp-web-home - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: ws.example.com -home_hostname: home.example.com -portal_hostname: portal.example.com -vendor: - protocol: http - hostname: vendors.example.com - port: 80 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: "" - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - - "" - - "" - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - - "" - - "" - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: true - hosts: - - host: home.example.com - paths: - - fullName: qxp-web-home - path: / - svcPort: 80 - - fullName: qxp-web-nginx - path: /dist - svcPort: 80 - - fullName: minio - path: /default - svcPort: 9000 -app: - kubernetes: - io: - name: fronted diff --git a/deployment/deployment/quanxiang_charts/qxp-web-nginx/Chart.yaml b/deployment/deployment/quanxiang_charts/qxp-web-nginx/Chart.yaml deleted file mode 100644 index 86076f7..0000000 --- a/deployment/deployment/quanxiang_charts/qxp-web-nginx/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: qxp-web-nginx -version: 0.1.0 diff --git a/deployment/deployment/quanxiang_charts/qxp-web-nginx/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/qxp-web-nginx/templates/NOTES.txt deleted file mode 100644 index 41faec5..0000000 --- a/deployment/deployment/quanxiang_charts/qxp-web-nginx/templates/NOTES.txt +++ /dev/null @@ -1,21 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "audit.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 }} - 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 "audit.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "audit.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "audit.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 port-forward $POD_NAME 8080:80 -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/qxp-web-nginx/values.yaml b/deployment/deployment/quanxiang_charts/qxp-web-nginx/values.yaml deleted file mode 100644 index 2c60df8..0000000 --- a/deployment/deployment/quanxiang_charts/qxp-web-nginx/values.yaml +++ /dev/null @@ -1,94 +0,0 @@ -image: - name: qxp-web-nginx - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: "" - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - - "" - - "" - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - - "" - - "" - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: - - host: chart-example.local - paths: [] -app: - kubernetes: - io: - name: fronted diff --git a/deployment/deployment/quanxiang_charts/qxp-web-portal/Chart.yaml b/deployment/deployment/quanxiang_charts/qxp-web-portal/Chart.yaml deleted file mode 100644 index 86076f7..0000000 --- a/deployment/deployment/quanxiang_charts/qxp-web-portal/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: qxp-web-nginx -version: 0.1.0 diff --git a/deployment/deployment/quanxiang_charts/qxp-web-portal/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/qxp-web-portal/templates/NOTES.txt deleted file mode 100644 index 41faec5..0000000 --- a/deployment/deployment/quanxiang_charts/qxp-web-portal/templates/NOTES.txt +++ /dev/null @@ -1,21 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "audit.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 }} - 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 "audit.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "audit.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "audit.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 port-forward $POD_NAME 8080:80 -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/qxp-web-portal/templates/_helpers.tpl b/deployment/deployment/quanxiang_charts/qxp-web-portal/templates/_helpers.tpl deleted file mode 100644 index ed71d56..0000000 --- a/deployment/deployment/quanxiang_charts/qxp-web-portal/templates/_helpers.tpl +++ /dev/null @@ -1,56 +0,0 @@ -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "audit.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 "audit.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "audit.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Common labels -*/}} -{{- define "audit.labels" -}} -app.kubernetes.io/name: {{ include "audit.name" . }} -helm.sh/chart: {{ include "audit.chart" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end -}} - -{{/* -Create the name of the service account to use -*/}} -{{- define "audit.serviceAccountName" -}} -{{- if .Values.serviceAccount.create -}} - {{ default (include "audit.fullname" .) .Values.serviceAccount.name }} -{{- else -}} - {{ default "default" .Values.serviceAccount.name }} -{{- end -}} -{{- end -}} diff --git a/deployment/deployment/quanxiang_charts/qxp-web-portal/values.yaml b/deployment/deployment/quanxiang_charts/qxp-web-portal/values.yaml deleted file mode 100644 index fc5e62f..0000000 --- a/deployment/deployment/quanxiang_charts/qxp-web-portal/values.yaml +++ /dev/null @@ -1,100 +0,0 @@ -image: - name: qxp-web-portal - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: ws.example.com -home_hostname: home.example.com -portal_hostname: portal.example.com -vendor: - protocol: http - hostname: vendors.example.com - port: 80 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: "" - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - - "" - - "" - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - - "" - - "" - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: true - hosts: - - host: portal.example.com - paths: - - fullName: qxp-web-portal - path: / - svcPort: 80 - - fullName: qxp-web-nginx - path: /dist - svcPort: 80 -app: - kubernetes: - io: - name: fronted diff --git a/deployment/deployment/quanxiang_charts/qxp-web-vendors/Chart.yaml b/deployment/deployment/quanxiang_charts/qxp-web-vendors/Chart.yaml deleted file mode 100644 index 0deeee2..0000000 --- a/deployment/deployment/quanxiang_charts/qxp-web-vendors/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: qxp-web-vendors -version: 0.1.0 diff --git a/deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/NOTES.txt deleted file mode 100644 index b578c92..0000000 --- a/deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/NOTES.txt +++ /dev/null @@ -1,21 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "audit.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 }} - 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 "audit.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "audit.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "audit.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 port-forward $POD_NAME 8080:80 -{{- end }} \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/_helpers.tpl b/deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/_helpers.tpl deleted file mode 100644 index ed71d56..0000000 --- a/deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/_helpers.tpl +++ /dev/null @@ -1,56 +0,0 @@ -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "audit.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 "audit.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "audit.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Common labels -*/}} -{{- define "audit.labels" -}} -app.kubernetes.io/name: {{ include "audit.name" . }} -helm.sh/chart: {{ include "audit.chart" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end -}} - -{{/* -Create the name of the service account to use -*/}} -{{- define "audit.serviceAccountName" -}} -{{- if .Values.serviceAccount.create -}} - {{ default (include "audit.fullname" .) .Values.serviceAccount.name }} -{{- else -}} - {{ default "default" .Values.serviceAccount.name }} -{{- end -}} -{{- end -}} diff --git a/deployment/deployment/quanxiang_charts/qxp-web-vendors/values.yaml b/deployment/deployment/quanxiang_charts/qxp-web-vendors/values.yaml deleted file mode 100644 index 8c59419..0000000 --- a/deployment/deployment/quanxiang_charts/qxp-web-vendors/values.yaml +++ /dev/null @@ -1,97 +0,0 @@ -image: - name: qxp-web-vendors - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: ws.test.com -home_hostname: home.test.com -portal_hostname: portal.test.com -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: "" - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - - "" - - "" - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - - "" - - "" - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: true - hosts: - - host: vendors.example.com - paths: - - fullName: qxp-web-vendors - path: / - svcPort: 80 -app: - kubernetes: - io: - name: fronted diff --git a/deployment/deployment/quanxiang_charts/search/Chart.yaml b/deployment/deployment/quanxiang_charts/search/Chart.yaml deleted file mode 100644 index 1ec0f84..0000000 --- a/deployment/deployment/quanxiang_charts/search/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "0.7.0" -description: A Helm chart for Kubernetes -name: nurturing -version: 0.7.0 diff --git a/deployment/deployment/quanxiang_charts/search/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/search/templates/NOTES.txt deleted file mode 100644 index bef0d1f..0000000 --- a/deployment/deployment/quanxiang_charts/search/templates/NOTES.txt +++ /dev/null @@ -1,21 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "nurturing.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 }} - 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 "nurturing.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "nurturing.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "nurturing.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 port-forward $POD_NAME 8080:80 -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/search/values.yaml b/deployment/deployment/quanxiang_charts/search/values.yaml deleted file mode 100644 index 7c26faf..0000000 --- a/deployment/deployment/quanxiang_charts/search/values.yaml +++ /dev/null @@ -1,92 +0,0 @@ -image: - name: search - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: "" - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - - "" - - "" - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - - 192.168.201.21:27017 - - 192.168.201.22:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: [] -app: - kubernetes: - io: - name: lowcode diff --git a/deployment/deployment/quanxiang_charts/serving/templates/secret.yaml b/deployment/deployment/quanxiang_charts/serving/templates/secret.yaml deleted file mode 100644 index aa3c036..0000000 --- a/deployment/deployment/quanxiang_charts/serving/templates/secret.yaml +++ /dev/null @@ -1,9 +0,0 @@ -{{- with .Values.dockerConfig }} -apiVersion: v1 -kind: Secret -type: kubernetes.io/dockerconfigjson -metadata: - name: {{ .name }} -data: - .dockerconfigjson: {{ .data }} -{{- end }} \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/serving/templates/serviceaccount.yaml b/deployment/deployment/quanxiang_charts/serving/templates/serviceaccount.yaml deleted file mode 100644 index 1fdc483..0000000 --- a/deployment/deployment/quanxiang_charts/serving/templates/serviceaccount.yaml +++ /dev/null @@ -1,18 +0,0 @@ -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "serving.serviceAccountName" . }} - labels: - {{- include "serving.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- if .Values.serviceAccount.secrets }} -secrets: - {{- range .Values.serviceAccount.secrets }} - - name: {{ .name }} - {{- end }} -{{- end }} -{{- end }} \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/serving/values.yaml b/deployment/deployment/quanxiang_charts/serving/values.yaml deleted file mode 100644 index 3174475..0000000 --- a/deployment/deployment/quanxiang_charts/serving/values.yaml +++ /dev/null @@ -1,88 +0,0 @@ -image: - name: "" - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: "" - port: 0 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: dispatcher - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: [] -app: - kubernetes: - io: - name: "" diff --git a/deployment/deployment/quanxiang_charts/warden/values.yaml b/deployment/deployment/quanxiang_charts/warden/values.yaml deleted file mode 100644 index c2f2c0f..0000000 --- a/deployment/deployment/quanxiang_charts/warden/values.yaml +++ /dev/null @@ -1,93 +0,0 @@ -image: - name: warden - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: c0b4d808-1b55-42fa-b12a-6149d716a88e - mysql: - db: "" - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: - - host: lowcode.quanxiangyun.com - paths: - - fullName: app-center - path: / - svcPort: 80 -app: - kubernetes: - io: - name: backend diff --git a/deployment/deployment/quanxiang_charts/web-process/Chart.yaml b/deployment/deployment/quanxiang_charts/web-process/Chart.yaml deleted file mode 100644 index 19ebf01..0000000 --- a/deployment/deployment/quanxiang_charts/web-process/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: fileserver -version: 0.1.0 diff --git a/deployment/deployment/quanxiang_charts/web-process/templates/NOTES.txt b/deployment/deployment/quanxiang_charts/web-process/templates/NOTES.txt deleted file mode 100644 index 78c54ae..0000000 --- a/deployment/deployment/quanxiang_charts/web-process/templates/NOTES.txt +++ /dev/null @@ -1,21 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "oauth2c.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 }} - 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 "oauth2c.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "oauth2c.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "oauth2c.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 port-forward $POD_NAME 8080:80 -{{- end }} diff --git a/deployment/deployment/quanxiang_charts/web-process/values.yaml b/deployment/deployment/quanxiang_charts/web-process/values.yaml deleted file mode 100644 index e36255e..0000000 --- a/deployment/deployment/quanxiang_charts/web-process/values.yaml +++ /dev/null @@ -1,93 +0,0 @@ -image: - name: web-processors - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -domain: example.com -mongo_host: "" -args: - enabled: true - endpoint: example.com:31198 - ip: xx.xx.xx.xx -kafka: - value: kafka.{{.}}.svc.cluster.local:9092 -redis: - host: "" - password: "" -imagePullSecrets: "" -service: - type: ClusterIP - port: 80 - rpcPort: 0 -nameOverride: "" -fullnameOverride: "" -websocket_hostname: "" -home_hostname: "" -portal_hostname: "" -vendor: - protocol: "" - hostname: "" - port: 0 -serviceAccount: - name: "" -podSecurityContext: {} -securityContext: {} -config: - jwtKey: "" - mysql: - db: fileserver - host: mysql.{{.}}.svc.cluster.local:3306 - user: root - password: qxp1234 - log: true - redis: - addrs: - - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 - username: "" - password: qxp1234 - elastic: - log: true - host: - - http://elasticsearch-master.{{.}}.svc.cluster.local:9200 - kafka: - broker: - - kafka.{{.}}.svc.cluster.local:9092 - mongo: - hosts: - - mongodb.{{.}}.svc.cluster.local:27017 - direct: false - credential: - authMechanism: SCRAM-SHA-1 - authSource: admin - username: root - password: qxp1234 - passwordSet: false - storage: - option: minio - urlExpire: 600 - partExpire: 604800 - launch: false - storages: - - name: minio - protocol: http - domain: home.qxp.com - accessKey: Minio - secretKey: Minio123456 - location: us-east-1 - bucketName: default - email: - emails: [] -ingress: - enabled: false - hosts: - - host: '*.fs.test.com' - paths: - - fullName: minio - path: / - svcPort: 9000 -app: - kubernetes: - io: - name: backend diff --git a/deployment/deployment/schemas/app_center.sql b/deployment/deployment/schemas/app_center.sql deleted file mode 100644 index 776ae1f..0000000 --- a/deployment/deployment/schemas/app_center.sql +++ /dev/null @@ -1,100 +0,0 @@ -/* - Navicat Premium Data Transfer - - Source Server : staging - Source Server Type : MySQL - Source Server Version : 50729 - Source Host : 192.168.208.253:3306 - Source Schema : app_center - - Target Server Type : MySQL - Target Server Version : 50729 - File Encoding : 65001 - - Date: 26/10/2021 15:47:39 -*/ - -CREATE DATABASE app_center; -USE app_center; - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - -create table t_app_center -( - id varchar(64) not null - primary key, - app_name varchar(80) null, - access_url varchar(200) null, - app_icon text null, - create_by varchar(64) null, - update_by varchar(64) null, - create_time bigint null, - update_time bigint null, - use_status bigint null, - constraint t_app_center_app_name_uindex - unique (app_name) -)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -create table t_app_user_relation -( - user_id varchar(64) null, - app_id varchar(64) null -)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -create table t_app_scope( - app_id varchar(64) null , - scope_id varchar(64) null -)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -ALTER table t_app_center ADD del_flag TINYINT; - -UPDATE t_app_center set del_flag = 0; - -ALTER table t_app_center ADD delete_time BIGINT; - -UPDATE t_app_center set delete_time = 0; - -DROP INDEX t_app_center_app_name_uindex ON t_app_center; - --- auto-generated definition -create table t_app_template -( - id varchar(64) not null, - name varchar(80) null comment 'template name', - app_icon text null comment 'app icon', - path varchar(200) null comment 'file server path', - source_id varchar(64) null comment 'source app id', - source_name varchar(80) null comment 'source app name', - version varchar(64) null comment 'template version', - group_id varchar(64) null comment 'group id', - created_by varchar(64) null, - created_name varchar(64) null, - created_time bigint null, - updated_by varchar(64) null, - updated_name varchar(64) null, - updated_time bigint null, - status int null comment 'publish status:0:private 1:public', - constraint t_app_template_id_uindex - unique (id) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 comment 'app template table'; - -alter table t_app_center add app_sign varchar(30) null; - -alter table t_app_template - add primary key (id); - - -alter table t_app_center - add extension text null; - -alter table t_app_center - add description text null; - - -ALTER TABLE t_app_center ADD COLUMN server INT COMMENT 'initialized modules of app' AFTER use_status; - -ALTER table t_app_center ADD per_poly BOOLEAN default false ; -ALTER table t_app_scope ADD type varchar(64) null; - --- update t_app_center set use_status = -5; diff --git a/deployment/deployment/schemas/application.sql b/deployment/deployment/schemas/application.sql deleted file mode 100644 index c926e6b..0000000 --- a/deployment/deployment/schemas/application.sql +++ /dev/null @@ -1,42 +0,0 @@ -/* - Navicat Premium Data Transfer - - Source Server : staging - Source Server Type : MySQL - Source Server Version : 50729 - Source Host : 192.168.208.253:3306 - Source Schema : application - - Target Server Type : MySQL - Target Server Version : 50729 - File Encoding : 65001 - - Date: 26/10/2021 15:52:16 -*/ -CREATE DATABASE application; -USE application; - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - --- ---------------------------- --- Table structure for application --- ---------------------------- -DROP TABLE IF EXISTS `application`; -CREATE TABLE `application` ( - `id` varchar(64) NOT NULL, - `application_name` varchar(50) DEFAULT NULL, - `application_describe` varchar(50) DEFAULT NULL, - `client_id` varchar(50) DEFAULT NULL, - `client_secret` varchar(64) DEFAULT NULL, - `domain` varchar(64) DEFAULT NULL, - `app_index_url` varchar(100) DEFAULT NULL, - `create_by` varchar(64) DEFAULT NULL, - `client_base_url` varchar(100) DEFAULT NULL, - `login_url` varchar(64) DEFAULT NULL, - `status` bigint(20) DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -SET FOREIGN_KEY_CHECKS = 1; -insert into application (id, application_name, application_describe, client_id, client_secret, domain, app_index_url, create_by, client_base_url, login_url, status) values ('sdvcvnshms124s', '测试应用', '测试', '000000', '999999', 'http://oauth2c', 'http://127.0.0.1:9099/test/index', null, 'http://oauth2c/api/v1/oauth2c', 'http://127.0.0.1:9095/loginhtml', 1); \ No newline at end of file diff --git a/deployment/deployment/schemas/dispatcher.sql b/deployment/deployment/schemas/dispatcher.sql deleted file mode 100644 index 64138b0..0000000 --- a/deployment/deployment/schemas/dispatcher.sql +++ /dev/null @@ -1,41 +0,0 @@ -/* - Navicat Premium Data Transfer - - Source Server : staging - Source Server Type : MySQL - Source Server Version : 50729 - Source Host : 192.168.208.253:3306 - Source Schema : dispatcher - - Target Server Type : MySQL - Target Server Version : 50729 - File Encoding : 65001 - - Date: 26/10/2021 15:52:57 -*/ -CREATE DATABASE dispatcher; -USE dispatcher; - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - --- ---------------------------- --- Table structure for task --- ---------------------------- -DROP TABLE IF EXISTS `task`; -CREATE TABLE `task` ( - `id` varchar(36) NOT NULL, - `title` varchar(120) DEFAULT NULL, - `describe` text, - `type` tinyint(1) NOT NULL, - `time_bar` varchar(24) DEFAULT NULL, - `state` tinyint(1) NOT NULL, - `code` varchar(55) NOT NULL, - `retry` int(2) DEFAULT NULL, - `retry_delay` int(6) DEFAULT NULL, - `created_at` bigint(20) NOT NULL, - `updated_at` bigint(20) DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -SET FOREIGN_KEY_CHECKS = 1; diff --git a/deployment/deployment/schemas/entrepot.sql b/deployment/deployment/schemas/entrepot.sql deleted file mode 100644 index 2ed1357..0000000 --- a/deployment/deployment/schemas/entrepot.sql +++ /dev/null @@ -1,32 +0,0 @@ -/*==============================================================*/ -/* DBMS name: MySQL 5.0 */ -/* Created on: 2021/3/28 20:01:33 */ -/*==============================================================*/ -CREATE DATABASE entrepot; -USE entrepot; - -DROP TABLE IF EXISTS `task`; - - -/*==============================================================*/ -/* Table: task */ -/*==============================================================*/ -CREATE TABLE `task` -( - `id` VARCHAR(36) NOT NULL COMMENT 'id', - `created_at` BIGINT(20) COMMENT 'create time', - `finish_at` BIGINT(20) COMMENT 'finish time', - `creator_id` VARCHAR(36) COMMENT 'creator id', - `creator_name` VARCHAR(16) COMMENT 'creator name', - `title` VARCHAR(64) COMMENT 'task title', - `types` VARCHAR(16) COMMENT 'form app org' , - `command` VARCHAR(16) COMMENT 'task command eg: formExport' , - `file_addr` VARCHAR(128) COMMENT 'task import file-server path', - `file_size` INT(11) COMMENT 'file size', - `file_opt` VARCHAR(16) COMMENT 'eg:mino ', - `value` TEXT COMMENT 'task parameter key value json', - `result` TEXT COMMENT 'task result key value json', - `status` SMALLINT COMMENT '1 ing ,2 success 3 fail', - `ratio` FLOAT COMMENT 'progress eg 50 is 50%', - PRIMARY KEY (`id`) -)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/deployment/deployment/schemas/faas.sql b/deployment/deployment/schemas/faas.sql deleted file mode 100644 index 62f80d0..0000000 --- a/deployment/deployment/schemas/faas.sql +++ /dev/null @@ -1,146 +0,0 @@ -CREATE DATABASE faas DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; - -use faas - -create table dockers -( - id varchar(64) not null - primary key, - host varchar(200) null, - user_name varchar(64) null, - name_space varchar(64) null, - secret text null, - name varchar(64) null, - created_at bigint null, - updated_at bigint null, - deleted_at bigint null, - created_by varchar(64) null, - updated_by varchar(64) null, - deleted_by varchar(64) null, - tenant_id varchar(64) null -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - -create table event -( - id varchar(64) not null comment 'unique id' - primary key, - name varchar(200) null comment 'name of event', - type varchar(64) null comment 'type of event', - state varchar(64) null comment 'state of event', - message varchar(512) null comment 'msg of async', - create_by varchar(64) null, - create_at bigint null comment 'create time', - update_at bigint null comment 'update time', - delete_at bigint null comment 'delete time' -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - -create table functions -( - id varchar(64) not null - primary key, - group_id varchar(64) null, - project_id varchar(64) null, - version varchar(200) null, - `describe` text null, - status varchar(200) null, - doc_status int null, - doc int null comment 'status of function doc', - env text null, - created_at bigint null, - updated_at bigint null, - deleted_at bigint null, - created_by varchar(64) null, - updated_by varchar(64) null, - deleted_by varchar(64) null, - tenant_id varchar(64) null, - resource_ref varchar(200) null, - name varchar(200) null, - built_at bigint null, - constraint functions_name_uindex - unique (name) -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - -create table gits -( - id varchar(64) not null - primary key, - host varchar(200) null, - token text null, - name varchar(200) null, - created_at bigint null, - updated_at bigint null, - deleted_at bigint null, - created_by varchar(64) null, - updated_by varchar(64) null, - deleted_by varchar(64) null, - tenant_id varchar(64) null, - known_hosts varchar(1000) null, - key_scan_known_hosts text, - ssh text null -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - -create table groups -( - id varchar(64) not null - primary key, - group_id int null, - group_name varchar(40) null, - Title varchar(64), - `describe` text null, - created_at bigint null, - updated_at bigint null, - created_by varchar(64) null, - updated_by varchar(64) null, - deleted_by varchar(64) null, - app_id varchar(64) null -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - -create table projects -( - id varchar(64) not null - primary key, - group_id varchar(64) null, - project_id int null, - project_name varchar(40) null, - alias varchar(40) null, - `describe` text null, - created_at bigint null, - updated_at bigint null, - created_by varchar(64) null, - updated_by varchar(64) null, - deleted_by varchar(64) null, - language varchar(20) null, - version varchar(30) null, - status int null, - user_id varchar(64) null, - repo_url text null -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - -create table users -( - id varchar(64) not null - primary key, - user_id varchar(64) null, - git_name varchar(64) null, - git_id int null, - created_at bigint null, - updated_at bigint null, - created_by varchar(64) null, - updated_by varchar(64) null, - deleted_by varchar(64) null, - token varchar(64) null -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - -create table user_group -( - id varchar(64) not null - primary key, - user_id varchar(64) null, - git_id int null, - group_id varchar(64) null, - created_at bigint null, - updated_at bigint null, - created_by varchar(64) null, - updated_by varchar(64) null, - deleted_by varchar(64) null -)ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/deployment/deployment/schemas/fileserver.sql b/deployment/deployment/schemas/fileserver.sql deleted file mode 100644 index 0066c4d..0000000 --- a/deployment/deployment/schemas/fileserver.sql +++ /dev/null @@ -1,90 +0,0 @@ -/* - Navicat Premium Data Transfer - - Source Server : staging - Source Server Type : MySQL - Source Server Version : 50729 - Source Host : 192.168.208.253:3306 - Source Schema : fileserver - - Target Server Type : MySQL - Target Server Version : 50729 - File Encoding : 65001 - - Date: 26/10/2021 15:53:45 -*/ -CREATE DATABASE fileserver; -USE fileserver; - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - --- ---------------------------- --- Table structure for fileserver --- ---------------------------- -CREATE TABLE `user` ( - `id` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'ID', - `file_name` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '文件名称', - `file_md5` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '文件唯一md5值', - `file_type` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '文件mime类型', - `file_time` int(11) NOT NULL DEFAULT 0 COMMENT '视频文件长度 单位秒', - `file_size` int(11) NOT NULL DEFAULT 0 COMMENT '文件大小 单位KB', - `file_number` int(11) NOT NULL DEFAULT 1 COMMENT '同一文件上传的个数', - `upload_name` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '文件上传保存的文件名', - `url` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'URL地址', - `create_at` bigint(20) NOT NULL COMMENT '创建时间', - `update_at` bigint(20) NOT NULL COMMENT '修改时间', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '文件上传表' ROW_FORMAT = DYNAMIC; - -CREATE TABLE `fileserver` ( - `id` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'ID', - `file_name` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '文件名称', - `file_md5` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '文件唯一md5值', - `file_type` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '文件mime类型', - `file_time` int(11) NOT NULL DEFAULT 0 COMMENT '视频文件长度 单位秒', - `file_size` int(11) NOT NULL DEFAULT 0 COMMENT '文件大小 单位KB', - `file_number` int(11) NOT NULL DEFAULT 1 COMMENT '同一文件上传的个数', - `upload_name` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '文件上传保存的文件名', - `url` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'URL地址', - `create_at` bigint(20) NOT NULL COMMENT '创建时间', - `update_at` bigint(20) NOT NULL COMMENT '修改时间', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '文件上传表' ROW_FORMAT = DYNAMIC; - --- 把表默认的字符集和所有字符列(CHAR,VARCHAR,TEXT)改为新的字符集 -ALTER TABLE `fileserver`.`fileserver` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - --- 修改 -ALTER TABLE `fileserver`.`fileserver` change `file_md5` `digest` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '文件唯一md5值'; -ALTER TABLE `fileserver`.`fileserver` change `file_type` `path` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '存储服务中的路径'; -ALTER TABLE `fileserver`.`fileserver` change `file_number` `number` int NOT NULL DEFAULT '1' COMMENT '同一文件上传的个数'; -ALTER TABLE `fileserver`.`fileserver` change `upload_name` `upload_id` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '分块上传uploadID'; -ALTER TABLE `fileserver`.`fileserver` change `file_size` `store_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '使用的存储配置名'; -ALTER TABLE `fileserver`.`fileserver` change `file_time` `upload_type` int NOT NULL COMMENT '上传的类型,1:文件上传,2:自定义页面上传'; - --- drop -ALTER TABLE `fileserver`.`fileserver` DROP `id`; -ALTER TABLE `fileserver`.`fileserver` DROP `url`; --- 查看相关表与字段编码 --- SHOW CREATE TABLE `user`; --- SHOW FULL COLUMNS FROM `user`; - - -ALTER TABLE `fileserver`.`fileserver` DROP `digest`; -ALTER TABLE `fileserver`.`fileserver` DROP `upload_type`; -ALTER TABLE `fileserver`.`fileserver` DROP `store_name`; -ALTER TABLE `fileserver`.`fileserver` DROP `upload_id`; -ALTER TABLE `fileserver`.`fileserver` DROP `number`; - --- ADD COLUMN -ALTER TABLE `fileserver`.`fileserver` ADD COLUMN `id` VARCHAR(36) FIRST; - -UPDATE `fileserver`.`fileserver` set `id` = UUID(); -DELETE FROM `fileserver`.`fileserver` WHERE `id` NOT IN ( - SELECT fs.minid FROM ( SELECT MIN(id) AS minid FROM `fileserver`.`fileserver` GROUP BY `path`) fs -); - --- ADD PRIMARY KEY and UNIQUE KEY -ALTER TABLE `fileserver`.`fileserver` ADD PRIMARY KEY(`id`); -ALTER TABLE `fileserver`.`fileserver` ADD UNIQUE UQE_PATH (`path`); diff --git a/deployment/deployment/schemas/flow.sql b/deployment/deployment/schemas/flow.sql deleted file mode 100644 index 2121ede..0000000 --- a/deployment/deployment/schemas/flow.sql +++ /dev/null @@ -1,334 +0,0 @@ -/* - Navicat Premium Data Transfer - - Source Server : staging - Source Server Type : MySQL - Source Server Version : 50729 - Source Host : 192.168.208.253:3306 - Source Schema : flow - - Target Server Type : MySQL - Target Server Version : 50729 - File Encoding : 65001 - - Date: 26/10/2021 15:55:52 -*/ - -CREATE DATABASE flow; -USE flow; - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - --- ---------------------------- --- Table structure for dispatcher_callback --- ---------------------------- -DROP TABLE IF EXISTS `dispatcher_callback`; -CREATE TABLE `dispatcher_callback` ( - `id` varchar(40) NOT NULL, - `type` varchar(10) NOT NULL COMMENT '回调类型', - `task_def_key` varchar(64) DEFAULT NULL, - `process_instance_id` varchar(64) DEFAULT NULL, - `other_info` varchar(255) DEFAULT NULL COMMENT '其他信息', - `creator_id` varchar(40) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '创建人', - `create_time` varchar(40) DEFAULT NULL COMMENT '创建时间', - `modifier_id` varchar(40) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '更新人', - `modify_time` varchar(40) DEFAULT NULL COMMENT '更新时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - --- ---------------------------- --- Table structure for flow --- ---------------------------- -DROP TABLE IF EXISTS `flow`; -CREATE TABLE `flow` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程id', - `app_id` varchar(100) NOT NULL DEFAULT '' COMMENT '应用id', - `source_id` varchar(100) NOT NULL DEFAULT '' COMMENT '源头流程id', - `name` varchar(50) NOT NULL DEFAULT '' COMMENT '流程名称', - `trigger_mode` varchar(10) NOT NULL DEFAULT '' COMMENT '触发方式', - `form_id` varchar(100) NOT NULL DEFAULT '', - `bpmn_text` text NOT NULL COMMENT '流程xml文件内容', - `process_key` varchar(200) NOT NULL DEFAULT '' COMMENT '流程key', - `status` varchar(10) NOT NULL DEFAULT '' COMMENT '状态', - `can_cancel` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否允许撤回', - `can_urge` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否允许催办', - `can_view_status_msg` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否允许查看状态和留言', - `can_msg` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否允许留言', - `can_cancel_type` tinyint(1) NOT NULL DEFAULT '1' COMMENT '允许撤回类型', - `can_cancel_nodes` varchar(1000) NOT NULL DEFAULT '' COMMENT '指定节点允许撤回', - `instance_name` varchar(1000) NOT NULL DEFAULT '' COMMENT '流程实例标题', - `key_fields` varchar(1000) NOT NULL DEFAULT '' COMMENT '流程摘要', - `process_id` varchar(40) NOT NULL DEFAULT '' COMMENT 'process中流程的id', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人', - `create_time` varchar(40) DEFAULT NULL COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人', - `modify_time` varchar(40) DEFAULT NULL COMMENT '更新时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='流程表'; - --- ---------------------------- --- Table structure for flow_abnormal_task --- ---------------------------- -DROP TABLE IF EXISTS `flow_abnormal_task`; -CREATE TABLE `flow_abnormal_task` ( - `id` varchar(40) NOT NULL DEFAULT '', - `flow_instance_id` varchar(100) NOT NULL DEFAULT '' COMMENT '流程实例id', - `process_instance_id` varchar(100) NOT NULL DEFAULT '' COMMENT 'camunda流程实例id', - `task_id` varchar(100) NOT NULL DEFAULT '' COMMENT '任务id', - `task_name` varchar(100) NOT NULL DEFAULT '' COMMENT '任务名称', - `task_def_key` varchar(100) NOT NULL DEFAULT '' COMMENT '任务key', - `reason` varchar(100) NOT NULL DEFAULT '' COMMENT '异常原因', - `remark` varchar(100) NOT NULL DEFAULT '' COMMENT '备注', - `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '状态', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人', - `create_time` varchar(40) DEFAULT NULL COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人', - `modify_time` varchar(40) DEFAULT NULL COMMENT '更新时间' -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='异常任务'; - --- ---------------------------- --- Table structure for flow_comment --- ---------------------------- -DROP TABLE IF EXISTS `flow_comment`; -CREATE TABLE `flow_comment` ( - `id` varchar(40) NOT NULL COMMENT '主键', - `flow_instance_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程实例id', - `comment_user_id` varchar(40) NOT NULL DEFAULT '' COMMENT '讨论人id', - `content` text NOT NULL COMMENT '讨论内容', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人', - `create_time` varchar(40) DEFAULT NULL COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人', - `modify_time` varchar(40) DEFAULT NULL COMMENT '更新时间', - PRIMARY KEY (`id`), - KEY `flow_comment_flow_instance_id_index` (`flow_instance_id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - --- ---------------------------- --- Table structure for flow_comment_attachment --- ---------------------------- -DROP TABLE IF EXISTS `flow_comment_attachment`; -CREATE TABLE `flow_comment_attachment` ( - `id` varchar(40) NOT NULL COMMENT '主键', - `flow_comment_id` varchar(40) NOT NULL COMMENT '流程讨论表id', - `attachment_name` varchar(300) NOT NULL DEFAULT '' COMMENT '附件名称', - `attachment_url` varchar(500) NOT NULL DEFAULT '' COMMENT '附件地址', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人', - `create_time` varchar(40) DEFAULT NULL COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人', - `modify_time` varchar(40) DEFAULT NULL COMMENT '更新时间', - PRIMARY KEY (`id`), - KEY `flow_comment_attachment_flow_comment_id_index` (`flow_comment_id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - --- ---------------------------- --- Table structure for flow_form_field --- ---------------------------- -DROP TABLE IF EXISTS `flow_form_field`; -CREATE TABLE `flow_form_field` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT '主键', - `flow_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程id', - `form_id` varchar(50) NOT NULL DEFAULT '' COMMENT '表单id', - `field_name` varchar(50) NOT NULL DEFAULT '' COMMENT '字段名', - `field_value_path` varchar(100) NOT NULL DEFAULT '' COMMENT '字段值path', - `creator_id` varchar(40) NOT NULL DEFAULT '', - `create_time` varchar(40) DEFAULT NULL, - `modifier_id` varchar(40) NOT NULL DEFAULT '', - `modify_time` varchar(40) DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `flow_id` (`flow_id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='工作流表单字段'; - --- ---------------------------- --- Table structure for flow_instance --- ---------------------------- -DROP TABLE IF EXISTS `flow_instance`; -CREATE TABLE `flow_instance` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程实例id', - `app_id` varchar(100) NOT NULL DEFAULT '' COMMENT '应用id', - `app_name` varchar(100) NOT NULL DEFAULT '' COMMENT '应用名称', - `flow_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程id', - `process_instance_id` varchar(100) NOT NULL DEFAULT '' COMMENT 'camunda流程实例id', - `form_id` varchar(100) DEFAULT '' COMMENT '表单id', - `form_instance_id` varchar(40) NOT NULL DEFAULT '' COMMENT '表单数据id', - `name` varchar(100) NOT NULL DEFAULT '' COMMENT '流程名称', - `apply_no` varchar(500) NOT NULL DEFAULT '' COMMENT '流水号', - `apply_user_id` varchar(40) NOT NULL DEFAULT '' COMMENT '申请人id', - `apply_user_name` varchar(100) NOT NULL DEFAULT '' COMMENT '申请人姓名', - `status` varchar(30) NOT NULL DEFAULT '' COMMENT '审批单状态', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人', - `create_time` varchar(40) DEFAULT NULL COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人', - `modify_time` varchar(40) DEFAULT NULL COMMENT '更新时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='流程实例'; - --- ---------------------------- --- Table structure for flow_instance_step --- ---------------------------- -DROP TABLE IF EXISTS `flow_instance_step`; -CREATE TABLE `flow_instance_step` ( - `id` varchar(64) NOT NULL COMMENT '主键', - `process_instance_id` varchar(64) NOT NULL DEFAULT '' COMMENT '流程实例id', - `task_id` varchar(64) NOT NULL DEFAULT '' COMMENT '任务id', - `task_type` varchar(20) NOT NULL DEFAULT '' COMMENT '节点类型:或签、会签、任填、全填、开始、结束', - `task_def_key` varchar(255) NOT NULL DEFAULT '' COMMENT '流程节点定义key', - `task_name` varchar(64) NOT NULL DEFAULT '' COMMENT '任务名称', - `node_instance_id` varchar(64) NOT NULL DEFAULT '' COMMENT '节点实例ID', - `handle_user_ids` varchar(4000) NOT NULL DEFAULT '' COMMENT '处理人', - `status` varchar(20) NOT NULL DEFAULT '' COMMENT '步骤处理结果,通过、拒绝、完成填写、已回退、打回重填、自动跳过、自动交给管理员', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人', - `create_time` varchar(40) DEFAULT NULL COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人', - `modify_time` varchar(40) DEFAULT NULL COMMENT '更新时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='流程实例步骤表'; - --- ---------------------------- --- Table structure for flow_instance_variables --- ---------------------------- -DROP TABLE IF EXISTS `flow_instance_variables`; -CREATE TABLE `flow_instance_variables` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT '主键', - `process_instance_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程实例id', - `name` varchar(50) NOT NULL DEFAULT '' COMMENT '变量名称SYSTEM:系统变量 CUSTOM:自定义变量', - `type` varchar(20) NOT NULL DEFAULT '' COMMENT '变量类型', - `code` varchar(50) NOT NULL DEFAULT '' COMMENT '变量标识', - `field_type` varchar(50) NOT NULL DEFAULT '' COMMENT '字段类型', - `format` varchar(50) NOT NULL DEFAULT '' COMMENT '字段格式', - `value` varchar(255) NOT NULL DEFAULT '' COMMENT '变量值', - `desc` varchar(255) NOT NULL DEFAULT '' COMMENT '注释', - `creator_id` varchar(40) NOT NULL DEFAULT '', - `create_time` varchar(40) DEFAULT NULL, - `modifier_id` varchar(40) NOT NULL DEFAULT '', - `modify_time` varchar(40) DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `flow_id` (`process_instance_id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='流程实例变量表'; - --- ---------------------------- --- Table structure for flow_operation_record --- ---------------------------- -DROP TABLE IF EXISTS `flow_operation_record`; -CREATE TABLE `flow_operation_record` ( - `id` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, - `process_instance_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', - `instance_step_id` varchar(64) NOT NULL DEFAULT '' COMMENT '流程实例环节表主键', - `handle_user_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '处理人', - `handle_type` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', - `handle_desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', - `task_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', - `task_name` varchar(100) NOT NULL DEFAULT '', - `task_def_key` varchar(255) NOT NULL DEFAULT '' COMMENT '任务定义的ID', - `remark` varchar(4000) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', - `correlation_data` text NOT NULL, - `status` varchar(20) NOT NULL DEFAULT '', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人', - `create_time` varchar(40) DEFAULT NULL COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人', - `modify_time` varchar(40) DEFAULT NULL COMMENT '更新时间', - `rel_node_def_key` varchar(255) NOT NULL DEFAULT '' COMMENT '关联的node节点' -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='流程操作记录'; - --- ---------------------------- --- Table structure for flow_trigger_rule --- ---------------------------- -DROP TABLE IF EXISTS `flow_trigger_rule`; -CREATE TABLE `flow_trigger_rule` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT 'id', - `flow_id` varchar(100) NOT NULL DEFAULT '' COMMENT '流程id', - `form_id` varchar(100) NOT NULL DEFAULT '' COMMENT '表单id', - `rule` text NOT NULL COMMENT '规则', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人', - `create_time` varchar(40) DEFAULT NULL COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人', - `modify_time` varchar(40) DEFAULT NULL COMMENT '更新时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='流程触发规则'; - --- ---------------------------- --- Table structure for flow_urge --- ---------------------------- -DROP TABLE IF EXISTS `flow_urge`; -CREATE TABLE `flow_urge` ( - `id` varchar(40) NOT NULL, - `task_id` varchar(64) DEFAULT NULL COMMENT '任务id', - `process_instance_id` varchar(64) DEFAULT NULL COMMENT '流程实例id', - `creator_id` varchar(40) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '创建人', - `create_time` varchar(40) DEFAULT NULL COMMENT '创建时间', - `modifier_id` varchar(40) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '更新人', - `modify_time` varchar(40) DEFAULT NULL COMMENT '更新时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - --- ---------------------------- --- Table structure for flow_variables --- ---------------------------- -DROP TABLE IF EXISTS `flow_variables`; -CREATE TABLE `flow_variables` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT '主键', - `flow_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程id', - `name` varchar(50) NOT NULL DEFAULT '' COMMENT '变量名称SYSTEM:系统变量 CUSTOM:自定义变量', - `type` varchar(20) NOT NULL DEFAULT '' COMMENT '变量类型', - `code` varchar(50) NOT NULL DEFAULT '' COMMENT '变量标识', - `field_type` varchar(50) NOT NULL DEFAULT '' COMMENT '字段类型', - `format` varchar(50) NOT NULL DEFAULT '' COMMENT '字段格式', - `default_value` varchar(255) NOT NULL DEFAULT '' COMMENT '默认值', - `desc` varchar(255) NOT NULL DEFAULT '' COMMENT '注释', - `creator_id` varchar(40) NOT NULL DEFAULT '', - `create_time` varchar(40) DEFAULT NULL, - `modifier_id` varchar(40) NOT NULL DEFAULT '', - `modify_time` varchar(40) DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `flow_id` (`flow_id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='工作流变量表'; - --- ---------------------------- --- Table structure for instance_execution --- ---------------------------- -DROP TABLE IF EXISTS `instance_execution`; -CREATE TABLE `instance_execution` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT '主键', - `process_instance_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程实例id', - `execution_id` varchar(50) NOT NULL DEFAULT '' COMMENT 'executionid', - `result` varchar(20) NOT NULL DEFAULT '' COMMENT '分支结果:通过、拒绝', - `creator_id` varchar(40) NOT NULL DEFAULT '', - `create_time` varchar(40) DEFAULT NULL, - `modifier_id` varchar(40) NOT NULL DEFAULT '', - `modify_time` varchar(40) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -SET FOREIGN_KEY_CHECKS = 1; - - -DROP TABLE IF EXISTS `flow_process_relation`; -CREATE TABLE `flow_process_relation` -( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程id', - `bpmn_text` text NOT NULL COMMENT '流程xml文件内容', - `flow_id` varchar(40) NOT NULL DEFAULT '' COMMENT 'flowID', - `process_id` varchar(40) NOT NULL DEFAULT '' COMMENT 'process中流程的id', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人', - `create_time` varchar(40) DEFAULT NULL COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人', - `modify_time` varchar(40) DEFAULT NULL COMMENT '更新时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='流程实例关系表'; - -INSERT INTO flow_variables (id,flow_id,name,`type`,code,field_type,format,default_value,`desc`,creator_id,create_time,modifier_id,modify_time) VALUES - ('1','0','流程发起人','SYSTEM','flowVar_instanceCreatorName','string','','','','0','2021-09-14T14:30:18+0000','0','2021-09-14T14:30:18+0000'), - ('2','0','流程发起时间','SYSTEM','flowVar_instanceCreateTime','datetime','','','','0','2021-09-14T14:30:18+0000','0','2021-09-14T14:30:18+0000'), - ('3','0','流程状态','SYSTEM','flowVar_instanceStatus','string','','','','0','2021-09-14T14:30:18+0000','0','2021-09-14T14:30:18+0000'); - -ALTER TABLE flow ADD app_status varchar(20) NOT NULL DEFAULT 'ACTIVE' COMMENT 'app状态' after app_id; -ALTER TABLE flow_instance ADD app_status varchar(20) NOT NULL DEFAULT 'ACTIVE' COMMENT 'app状态' after app_id; - -alter table flow add cron varchar(20) null; - -alter table flow_variables - modify code varchar(200) default '' not null comment '变量标识'; - -alter table flow_instance_variables - modify code varchar(200) default '' not null comment '变量标识'; - -alter table flow_instance add request_id varchar(200) null; diff --git a/deployment/deployment/schemas/form.sql b/deployment/deployment/schemas/form.sql deleted file mode 100644 index 74f70d8..0000000 --- a/deployment/deployment/schemas/form.sql +++ /dev/null @@ -1,115 +0,0 @@ -CREATE DATABASE form; -USE form; - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - -DROP TABLE IF EXISTS `role`; -CREATE TABLE `role` ( - `id` VARCHAR(64) COMMENT 'unique id', - `app_id` VARCHAR(64) NOT NULL COMMENT 'app id', - `name` VARCHAR(64) NOT NULL COMMENT 'permit group name', - `description` VARCHAR(255) COMMENT 'description', - `created_at` BIGINT(20) COMMENT 'create time', - `creator_id` VARCHAR(36) COMMENT 'creator id', - `creator_name` VARCHAR(16) COMMENT 'creator name', - `types` TINYINT(1) COMMENT 'types 1 init 2 create', - - PRIMARY KEY (`id`) -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `role_grant`; -CREATE TABLE `role_grant` ( - `id` VARCHAR(64) COMMENT 'unique id', - `role_id` VARCHAR(64) NOT NULL COMMENT 'role id', - `owner` VARCHAR(64) NOT NULL COMMENT 'owner id', - `owner_name` VARCHAR(64) NOT NULL COMMENT 'owner_nam', - `types` TINYINT(1) COMMENT 'types 1 init 2 create', - `app_id` VARCHAR(64) COMMENT 'types 1 init 2 create', - `created_at` BIGINT(20) COMMENT 'create time', - UNIQUE KEY `idx_global_name` (`role_id`, `owner`,`types`), - PRIMARY KEY (`id`) - -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `permit`; -CREATE TABLE `permit` ( - `id` VARCHAR(64) COMMENT 'unique id', - `role_id` VARCHAR(64) COMMENT 'authority' , - `path` VARCHAR(255) NOT NULL COMMENT 'path', - `method` VARCHAR(100) COMMENT 'method', - `params` TEXT COMMENT 'params', - `response` TEXT COMMENT 'response', - `condition` TEXT COMMENT 'conditions', - `created_at` BIGINT(20) COMMENT 'create time', - `creator_id` VARCHAR(36) COMMENT 'creator id', - `creator_name` VARCHAR(16) COMMENT 'creator name', - UNIQUE KEY `idx_global_name` (`role_id`, `path`), - PRIMARY KEY (`id`) -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `table`; - -CREATE TABLE `table` ( - `id` VARCHAR(64) COMMENT ' id', - `app_id` VARCHAR(64) NOT NULL COMMENT 'table is which app', - `table_id` VARCHAR(64) NOT NULL COMMENT 'tableID', - `schema` TEXT COMMENT 'web schema' , - `config` TEXT COMMENT 'config', - `created_at` BIGINT(20) COMMENT 'create time', - UNIQUE KEY `idx_global_name` (`app_id`, `table_id`), - PRIMARY KEY (`id`) -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `table_schema`; - -CREATE TABLE `table_schema` ( - `id` VARCHAR(64) COMMENT ' id', - `app_id` VARCHAR(64) NOT NULL COMMENT 'table is which app', - `table_id` VARCHAR(64) NOT NULL COMMENT 'table id', - `title` VARCHAR(32) COMMENT 'title', - `field_len` INT COMMENT 'field_len' , - `description` VARCHAR(100) COMMENT 'description', - `source` TINYINT(1) COMMENT 'source', - `created_at` BIGINT(20) COMMENT 'create time', - `updated_at` BIGINT(20) COMMENT 'update time', - `creator_id` VARCHAR(36) COMMENT 'creator id', - `creator_name` VARCHAR(16) COMMENT 'creator name', - `editor_id` VARCHAR(36) COMMENT 'editor id', - `editor_name` VARCHAR(16) COMMENT 'editor name', - `schema` TEXT COMMENT 'web schema' , - UNIQUE KEY `idx_global_name` (`app_id`, `table_id`), - PRIMARY KEY (`id`) -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - - - -DROP TABLE IF EXISTS `table_relation`; -CREATE TABLE `table_relation` ( - `id` VARCHAR(64) COMMENT ' id', - `app_id` VARCHAR(64) NOT NULL COMMENT 'table is which one app', - `table_id` VARCHAR(64) NOT NULL COMMENT 'tableID', - `field_name` VARCHAR(64) COMMENT 'field name' , - `sub_table_id` VARCHAR(64) COMMENT 'sub table id' , - `sub_table_type` VARCHAR(64) COMMENT 'sub table type', - `filter` VARCHAR(255) COMMENT 'filter', - `created_at` BIGINT(20) COMMENT 'create time', - PRIMARY KEY (`id`) -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `user_role`; -CREATE TABLE `user_role` ( - `id` VARCHAR(64) COMMENT ' id', - `app_id` VARCHAR(64) NOT NULL COMMENT 'app id', - `user_id` VARCHAR(64) NOT NULL COMMENT 'user id', - `role_id` VARCHAR(64) COMMENT 'role id' , - PRIMARY KEY (`id`) -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - -ALTER TABLE `permit` ADD `params_all` bool; -ALTER TABLE `permit` ADD `response_all` bool; \ No newline at end of file diff --git a/deployment/deployment/schemas/goalie.sql b/deployment/deployment/schemas/goalie.sql deleted file mode 100644 index 8b18927..0000000 --- a/deployment/deployment/schemas/goalie.sql +++ /dev/null @@ -1,362 +0,0 @@ -/* - Navicat Premium Data Transfer - - Source Server : staging - Source Server Type : MySQL - Source Server Version : 50729 - Source Host : 192.168.208.253:3306 - Source Schema : goalie - - Target Server Type : MySQL - Target Server Version : 50729 - File Encoding : 65001 - - Date: 26/10/2021 16:00:30 -*/ - -CREATE DATABASE goalie; -USE goalie; - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - --- ---------------------------- --- Table structure for func --- ---------------------------- -DROP TABLE IF EXISTS `func`; -CREATE TABLE `func` ( - `id` varchar(36) NOT NULL, - `p_id` varchar(36) DEFAULT NULL, - `func_tag` varchar(255) NOT NULL, - `name` varchar(60) NOT NULL, - `describe` text, - `created_at` bigint(20) NOT NULL, - `updated_at` bigint(20) NOT NULL, - PRIMARY KEY (`id`), - KEY `nk_func_pid` (`p_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - --- ---------------------------- --- Table structure for role --- ---------------------------- -DROP TABLE IF EXISTS `role`; -CREATE TABLE `role` ( - `id` varchar(36) NOT NULL, - `name` varchar(30) NOT NULL, - `tag` varchar(24) NOT NULL, - `created_at` bigint(20) NOT NULL, - `updated_at` bigint(20) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `uk_role_name` (`name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - --- ---------------------------- --- Table structure for role_func --- ---------------------------- -DROP TABLE IF EXISTS `role_func`; -CREATE TABLE `role_func` ( - `id` varchar(36) NOT NULL, - `role_id` varchar(36) NOT NULL, - `func_id` varchar(36) NOT NULL, - `created_at` bigint(20) NOT NULL, - `updated_at` bigint(20) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `uk_role_func` (`role_id`,`func_id`), - KEY `nk_role` (`role_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - --- ---------------------------- --- Table structure for role_owner --- ---------------------------- -DROP TABLE IF EXISTS `role_owner`; -CREATE TABLE `role_owner` ( - `id` varchar(36) NOT NULL, - `role_id` varchar(36) NOT NULL, - `type` tinyint(1) NOT NULL, - `owner_id` varchar(36) NOT NULL, - `created_at` bigint(20) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `uk_role_owner` (`role_id`,`owner_id`), - KEY `nk_role` (`role_id`), - KEY `nk_owner` (`owner_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -SET FOREIGN_KEY_CHECKS = 1; -BEGIN; -INSERT INTO `role` (`id`, `name`,`tag`,`created_at`,`updated_at`) - VALUES ("1","超级管理员","super",0,0); -INSERT INTO `role` (`id`, `name`,`tag`,`created_at`,`updated_at`) - VALUES ("2","管理员","warden",0,0); -INSERT INTO `role` (`id`, `name`,`tag`,`created_at`,`updated_at`) - VALUES ("3","查看者","viewer",0,0); -COMMIT; -BEGIN; --- 应用管理 -- -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("1","","application","应用管理","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("101","1","application/read","查看应用","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("102","1","application/create","新建应用","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("103","1","application/update","修改应用","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("104","1","application/delete","删除应用","",0,0); --- 访问控制 -- -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("2","","accessControl","访问控制","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("201","2","accessControl/mailList/read","查看企业通讯录","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("202","2","accessControl/mailList/manage","管理企业通讯录","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("203","2","accessControl/role/read","查看角色","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("204","2","accessControl/role/manage","管理角色","",0,0); --- 平台设置 -- -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("3","","platform","平台设置","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("301","3","platform/read","查看平台设置","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("302","3","platform/mangage","管理平台设置","",0,0); -COMMIT; -BEGIN; -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("1","1","1",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("2","1","101",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("3","1","102",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("4","1","103",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("5","1","104",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("6","1","2",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("7","1","201",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("8","1","202",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("9","1","203",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("10","1","204",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("11","1","3",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("12","1","301",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("13","1","302",0,0); -COMMIT; - -BEGIN; -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("14","2","1",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("15","2","101",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("16","2","102",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("17","2","103",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("18","2","104",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("19","2","2",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("20","2","201",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("21","2","202",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("22","2","203",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("23","2","204",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("24","2","3",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("25","2","301",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("26","2","302",0,0); -COMMIT; -BEGIN; -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("27","3","1",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("28","3","101",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("29","3","2",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("30","3","201",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("31","3","203",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("32","3","3",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("33","3","301",0,0); -COMMIT; -BEGIN; -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("4","","system","系统设置","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("401","4","system/read","消息查看","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("402","4","system/mangage","消息管理","",0,0); -COMMIT; -BEGIN; -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("34","1","4",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("35","1","401",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("36","1","402",0,0); -COMMIT; - -BEGIN; -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("37","2","4",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("38","2","401",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("39","2","402",0,0); -COMMIT; - -BEGIN; -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("40","3","4",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("41","3","401",0,0); -COMMIT; --- 操作日志 --- -BEGIN; -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("5","","audit","操作日志","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("501","5","audit/read","查看","",0,0); -COMMIT; - --- 赋予超级管理员权限 -- -BEGIN; -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("42","1","5",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("43","1","501",0,0); -COMMIT; - --- 赋予管理员权限 -- -BEGIN; -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("44","2","5",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("45","2","501",0,0); -COMMIT; - --- 赋予观察这权限 -- -BEGIN; -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("46","3","5",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("47","3","501",0,0); -COMMIT; - --- 数据集 --- -BEGIN; -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("6","","system","数据集","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("601","6","dataset/read","查看","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("602","6","dataset/create","新建","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("603","6","dataset/update","修改","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("604","6","dataset/delete","删除","",0,0); -COMMIT; - --- 赋予超级管理员权限 -- -BEGIN; -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("48","1","6",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("49","1","601",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("50","1","602",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("51","1","603",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("52","1","604",0,0); -COMMIT; - --- 赋予管理员权限 -- -BEGIN; -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("53","2","6",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("54","2","601",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("55","2","602",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("56","2","603",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("57","2","604",0,0); -COMMIT; - --- 赋予观察这权限 -- -BEGIN; -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("58","3","6",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("59","3","601",0,0); -COMMIT; - - --- 异常流程 --- -BEGIN; -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("7","","abnormalFlow","异常流程","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("701","7","abnormalFlow/read","查看","",0,0); -INSERT INTO `func` (`id`, `p_id`,`func_tag`,`name`,`describe`,`created_at`,`updated_at`) - VALUES ("702","7","abnormalFlow/dispose","处理","",0,0); -COMMIT; - --- 赋予超级管理员权限 -- -BEGIN; -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("60","1","7",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("61","1","701",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("62","1","702",0,0); -COMMIT; - --- 赋予管理员权限 -- -BEGIN; -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("63","2","7",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("64","2","701",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("65","2","702",0,0); -COMMIT; - --- 赋予观察这权限 -- -BEGIN; -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("66","3","7",0,0); -INSERT INTO `role_func` (`id`, `role_id`,`func_id`,`created_at`,`updated_at`) - VALUES ("67","3","701",0,0); -COMMIT; - --- insert into role_owner (`id`, `role_id`, `type`, `owner_id`, `created_at`)values ('1', '1', '1', 'admin',0); - --- update func set created_at=1629257919 where p_id!='' or p_id is not null - --- 默认超管 -- -insert into role_owner (`id`, `role_id`, `type`, `owner_id`, `created_at`)values ('1', '1', '1', '1',0); - --- role 新增字段 -- -alter table role add created_by varchar(64) null; - -alter table role add updated_by varchar(64) null; - -alter table role add tenant_id varchar(64) null; diff --git a/deployment/deployment/schemas/kms.sql b/deployment/deployment/schemas/kms.sql deleted file mode 100644 index 244fe56..0000000 --- a/deployment/deployment/schemas/kms.sql +++ /dev/null @@ -1,62 +0,0 @@ -CREATE DATABASE kms; -USE kms; - -DROP TABLE IF EXISTS secret_key; -CREATE TABLE `secret_key` ( - `id` VARCHAR(64) COMMENT 'unique id', - `owner` VARCHAR(64) COMMENT 'owner id', - `owner_name` VARCHAR(64) COMMENT 'owner name', - `name` VARCHAR(64), - `title` VARCHAR(64), - `description` VARCHAR(255), - `key_id` VARCHAR(128) NOT NULL, - `key_secret` VARCHAR(128) NOT NULL, - `active` INT(11) NOT NULL COMMENT '1 active 0 disable', - `assignee` VARCHAR(64) COMMENT 'assignee name', - `create_at` BIGINT(20) COMMENT 'create time', - `update_at` BIGINT(20) COMMENT 'update time', - `delete_at` BIGINT(20) COMMENT 'delete time', - UNIQUE KEY `idx_key_id` (`key_id`), - PRIMARY KEY (`id`) -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `customer_secret_key`; -CREATE TABLE `customer_secret_key` ( - `id` VARCHAR(64) COMMENT 'unique id', - `owner` VARCHAR(64) COMMENT 'owner id', - `owner_name` VARCHAR(64) COMMENT 'owner name', - `name` VARCHAR(128), - `title` VARCHAR(128), - `description` VARCHAR(255), - `service` VARCHAR(128) NOT NULL COMMENT 'belong service, eg: system_form', - `host` VARCHAR(256) NOT NULL COMMENT 'service host, eg: api.xxx.com:8080', - `auth_type` VARCHAR(64) NOT NULL COMMENT 'signature/cookie/oauth2...', - `auth_content` TEXT NOT NULL COMMENT 'authorize detail', - `key_id` VARCHAR(512) NOT NULL, - `key_secret` TEXT NOT NULL COMMENT 'crypt key secret', - `key_content` TEXT NOT NULL COMMENT 'key content', - `active` INT(11) NOT NULL COMMENT '1 active 0 disable', - `parsed` INT(11) NOT NULL COMMENT '1 parsed 0 not parse', - `create_at` BIGINT(20) COMMENT 'create time', - `update_at` BIGINT(20) COMMENT 'update time', - `delete_at` BIGINT(20) COMMENT 'delete time', - UNIQUE KEY `idx_global_key`(`service`,`key_id`), - PRIMARY KEY (`id`) -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `secret_key_config`; -CREATE TABLE `secret_key_config` ( - `id` VARCHAR(64) COMMENT 'unique id', - `owner` VARCHAR(64) NOT NULL COMMENT 'owner id', - `owner_name` VARCHAR(64) NOT NULL COMMENT 'owner name', - `config_content` VARCHAR(64) NOT NULL COMMENT 'config content', - `create_at` BIGINT(20) COMMENT 'create time', - `update_at` BIGINT(20) COMMENT 'update time', - `delete_at` BIGINT(20) COMMENT 'delete time', - UNIQUE KEY `idx_owner`(`owner`), - PRIMARY KEY (`id`) -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - -REPLACE INTO `secret_key_config` VALUES ('1', 'system', '系统', '{"keyNum": "5"}', unix_timestamp(NOW())*1000, unix_timestamp(NOW())*1000, NULL) diff --git a/deployment/deployment/schemas/message.sql b/deployment/deployment/schemas/message.sql deleted file mode 100644 index 4533982..0000000 --- a/deployment/deployment/schemas/message.sql +++ /dev/null @@ -1,92 +0,0 @@ -/* - Navicat Premium Data Transfer - - Source Server : staging - Source Server Type : MySQL - Source Server Version : 50729 - Source Host : 192.168.208.253:3306 - Source Schema : message - - Target Server Type : MySQL - Target Server Version : 50729 - File Encoding : 65001 - - Date: 26/10/2021 16:01:10 -*/ -CREATE DATABASE message; -USE message; - - -/*==============================================================*/ -/* DBMS name: MySQL 5.0 */ -/* Created on: 2021/3/28 20:01:33 */ -/*==============================================================*/ - - -DROP TABLE IF EXISTS `message_list`; - -DROP TABLE IF EXISTS `record`; - -DROP TABLE IF EXISTS `template`; - -/*==============================================================*/ -/* Table: message_list */ -/*==============================================================*/ -CREATE TABLE `message_list` -( - `id` VARCHAR(36) NOT NULL, - `title` VARCHAR(100), - `content` TEXT, - `creator_id` VARCHAR(36), - `creator_name` VARCHAR(30), - `types` SMALLINT, - `status` SMALLINT, - `receivers` TEXT, - `send_num` SMALLINT, - `success` SMALLINT, - `fail` SMALLINT, - `files` TEXT, - `created_at` BIGINT(20), - PRIMARY KEY (`id`) -)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -/*==============================================================*/ -/* Table: messsage_send */ -/*==============================================================*/ -create table `record` -( - `id` VARCHAR(36) NOT NULL, - `list_id` VARCHAR(36), - `receiver_id` VARCHAR(36), - `receiver_name` VARCHAR(30), - `read_status` SMALLINT, - `types` SMALLINT, - `created_at` BIGINT(20), - PRIMARY KEY(`id`) -)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - - -CREATE TABLE `template` ( - `id` VARCHAR(36) NOT NULL, - `name` VARCHAR(255) NOT NULL, - `title` VARCHAR(255) NOT NULL, - `content` VARCHAR(255) NOT NULL, - `created_at` BIGINT(20) , - `updated_at` BIGINT(20) , - `create_by` VARCHAR(255), - `status` INT, - PRIMARY KEY (`id`) -)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - --- ---------------------------- --- Records of template --- ---------------------------- -INSERT INTO `template` VALUES ('quanliang', '全量模板', '111', '{{.code}}', NULL, NULL, NULL, NULL); - -INSERT INTO `template` VALUES ('org_logincode', '登录验证码', '登录验证码', '您好:
您正在登录全象云系统,你的验证码是:{{.code}} 【有效期5分钟】', NULL, NULL, NULL, NULL); - -INSERT INTO `template` VALUES ('org_resetcode', '重置验证码', '重置验证码', '您好:
您正在重置您的全象云系统登录密码,你的验证码是:{{.code}} 【有效期5分钟】', NULL, NULL, NULL, NULL); - -INSERT INTO `template` VALUES ('org_forgetcode', '找回验证码', '找回验证码', '您好:
您正在找回全象云系统密码,你的验证码是:{{.code}} 【有效期5分钟】', NULL, NULL, NULL, NULL); - -INSERT INTO `template` VALUES ('org_resetpwd', '密码提示', '密码提示', '您好:
您正在使用全象云系统,当前最新的密码是 {{.code}}', NULL, NULL, NULL, NULL); \ No newline at end of file diff --git a/deployment/deployment/schemas/organizations.sql b/deployment/deployment/schemas/organizations.sql deleted file mode 100644 index 08f3baa..0000000 --- a/deployment/deployment/schemas/organizations.sql +++ /dev/null @@ -1,210 +0,0 @@ -/* - Navicat Premium Data Transfer - - Source Server : staging - Source Server Type : MySQL - Source Server Version : 50729 - Source Host : 192.168.208.253:3306 - Source Schema : organizations - - Target Server Type : MySQL - Target Server Version : 50729 - File Encoding : 65001 - - Date: 26/10/2021 16:01:28 -*/ -CREATE DATABASE organizations; -USE organizations; - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - -create table org_department -( - id varchar(64) not null - primary key, - name varchar(64) null, - use_status bigint null, - attr bigint null, - pid varchar(64) null, - super_pid varchar(64) null, - grade bigint null, - created_at bigint null, - updated_at bigint null, - deleted_at bigint null, - created_by varchar(64) null, - updated_by varchar(64) null, - deleted_by varchar(64) null, - tenant_id varchar(64) null -)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -create table org_use_columns -( - id varchar(64) not null - primary key, - column_id varchar(64) null, - viewer_status int(4) null, - tenant_id varchar(64) null -)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -create table org_user -( - id varchar(64) not null - primary key, - name varchar(64) null, - phone varchar(64) null, - email varchar(64) null, - self_email varchar(64) null, - id_card varchar(64) null, - address varchar(200) null, - use_status int(4) null, - tenant_id varchar(64) null, - position varchar(64) null, - avatar text null, - job_number text null, - gender int(4) null, - source varchar(64) null, - password_status int(4) null, - created_at bigint null, - updated_at bigint null, - deleted_at bigint null, - created_by varchar(64) null, - updated_by varchar(64) null, - deleted_by varchar(64) null -)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -create unique index org_user_email_uindex - on org_user (email); - - -create table org_user_account -( - id varchar(100) not null - primary key, - account varchar(100) null, - user_id varchar(64) null, - password varchar(100) null, - created_at bigint null, - updated_at bigint null, - deleted_at bigint null, - created_by varchar(64) null, - updated_by varchar(64) null, - deleted_by varchar(64) null, - tenant_id varchar(64) null -)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -create unique index org_user_account_account_uindex - on org_user_account (account); - -create table org_user_department_relation -( - id varchar(64) not null - primary key, - user_id varchar(64) null, - dep_id varchar(64) null, - attr varchar(64) null -)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -create table org_user_table_columns -( - id varchar(64) not null - primary key, - name varchar(64) null, - columns_name varchar(64) null, - types varchar(64) null, - len bigint null, - point_len bigint null, - attr bigint null, - status bigint null, - format varchar(64) null, - tenant_id varchar(64) null, - created_at bigint null, - updated_at bigint null, - deleted_at bigint null, - created_by varchar(64) null, - updated_by varchar(64) null, - deleted_by varchar(64) null -)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -create index columns_name - on org_user_table_columns (columns_name); - -create table org_user_tenant_relation -( - id varchar(64) not null - primary key, - user_id varchar(64) null, - tenant_id varchar(64) null, - status bigint null -)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -create table org_oct_use_columns -( - id varchar(64) not null - primary key, - column_id varchar(64) null, - created_at bigint null, - updated_at bigint null, - viewer_status int(4) null, - created_by varchar(64) null, - updated_bt varchar(64) null, - tenant_id varchar(64) null -)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -create table org_oct_user_table_columns -( - id varchar(64) not null - primary key, - name varchar(64) null, - columns_name varchar(64) null, - types varchar(64) null, - len bigint null, - point_len bigint null, - attr bigint null, - status bigint null, - created_at bigint null, - updated_at bigint null, - deleted_at bigint null, - created_by varchar(64) null, - updated_by varchar(64) null, - deleted_by varchar(64) null, - tenant_id varchar(64) null, - format varchar(64) null -)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -create index columns_name - on org_oct_user_table_columns (columns_name); - -create table org_user_leader_relation -( - id varchar(64) not null - primary key, - user_id varchar(64) null, - leader_id varchar(64) null, - attr varchar(256) null -)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - --- 超管数据 -INSERT INTO org_user -(id, name, phone, email, self_email, id_card, address, use_status, tenant_id, position, avatar, job_number, gender, source, password_status, created_at, updated_at, deleted_at, created_by, updated_by, deleted_by) -VALUES - ('1', 'SuperAdmin', '13888886666', 'admin@quanxiang.dev', 'admin@quanxiang.dev', '', '', 1, '', '', '', '', 1, '', 1, 1649429260908, 1649433071, 0, '', '', ''); - - -INSERT INTO org_department -(id, name, use_status, attr, pid, super_pid, grade, created_at, updated_at, deleted_at, created_by, updated_by, deleted_by, tenant_id) -VALUES - ('1', 'QCC', 1, 1, '', '1', 1, 1641966964, 1649433066, 0, '', '', '', ''); - - --- 密码 654321a.. -INSERT INTO org_user_account -(id, account, user_id, password, created_at, updated_at, deleted_at, created_by, updated_by, deleted_by, tenant_id) -VALUES - ('1', 'admin@quanxiang.dev', '1', '24d04ec3c9f0e285791035a47ba3e61a', 1635761030, 1649433067, 0, '', '', '', ''); - - - - -INSERT INTO org_user_department_relation (id, user_id, dep_id, attr) -VALUES ('1', '1', '1', '直属领导'); \ No newline at end of file diff --git a/deployment/deployment/schemas/polyapi.sql b/deployment/deployment/schemas/polyapi.sql deleted file mode 100644 index c3dfdb7..0000000 --- a/deployment/deployment/schemas/polyapi.sql +++ /dev/null @@ -1,308 +0,0 @@ -CREATE DATABASE polyapi; -USE polyapi; - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - -/*--------------------------------------------------------------------------------------------------------------------------*/ -DROP TABLE IF EXISTS `api_namespace`; -CREATE TABLE `api_namespace` ( - `id` VARCHAR(64) NOT NULL COMMENT 'unique id', - `owner` VARCHAR(64) COMMENT 'owner id', - `owner_name` VARCHAR(64) COMMENT 'owner name', - `parent` VARCHAR(320) NOT NULL DEFAULT '' COMMENT 'full namespace path, eg: /a/b/c', - `namespace` VARCHAR(64) NOT NULL COMMENT 'global namespace, inmutable', - `sub_count` INT(10) DEFAULT 0 NOT NULL COMMENT 'count of sub namespace', - `title` VARCHAR(64) COMMENT 'alias of namespace, mutable', - `desc` TEXT, - - `access` INT(11) NOT NULL COMMENT 'privilege for public access, 1,2,4,8,16,32 CRUDGX', - `active` TINYINT DEFAULT 1 COMMENT '1 ok, 0 disable', - `valid` TINYINT DEFAULT 1 COMMENT '1 valid, 0 invalid', - - `create_at` BIGINT(20) COMMENT 'create time', - `update_at` BIGINT(20) COMMENT 'update time', - `delete_at` BIGINT(20) COMMENT 'delete time', - UNIQUE KEY `idx_global_name` (`parent`, `namespace`), - PRIMARY KEY (`id`) -)ENGINE=INNODB DEFAULT CHARSET=utf8; - -/*--------------------------------------------------------------------------------------------------------------------------*/ -DROP TABLE IF EXISTS `api_service`; -CREATE TABLE `api_service` ( - `id` VARCHAR(64) COMMENT 'unique id', - `owner` VARCHAR(64) COMMENT 'owner id', - `owner_name` VARCHAR(64) COMMENT 'owner name', - `namespace` VARCHAR(384) NOT NULL COMMENT 'full namespace path, eg: a/b/c', - `name` VARCHAR(64) NOT NULL COMMENT 'service name, unique in namespace', - `title` VARCHAR(64) COMMENT 'alias of service, mutable', - `desc` TEXT, - - `access` INT(11) NOT NULL COMMENT 'privilege for public access, 1,2,4,8,16,32 CRUDGX', - `active` TINYINT DEFAULT 1 COMMENT '1 ok, 0 disable', - `schema` VARCHAR(16) NOT NULL COMMENT 'http/https', - `host` VARCHAR(128) NOT NULL COMMENT 'eg: api.xxx.com:8080', - `auth_type` VARCHAR(32) NOT NULL COMMENT 'none/system/signature/cookie/oauth2...', - `authorize` TEXT COMMENT 'JSON', - - `create_at` BIGINT(20) COMMENT 'create time', - `update_at` BIGINT(20) COMMENT 'update time', - `delete_at` BIGINT(20) COMMENT 'delete time', - UNIQUE KEY `idx_global_name` (`namespace`, `name`), - PRIMARY KEY (`id`) -)ENGINE=INNODB DEFAULT CHARSET=utf8; - -REPLACE INTO `api_namespace`(`id`,`owner`,`owner_name`,`parent`,`namespace`,`title`,`desc`,`access`,`active`,`create_at`,`update_at`,`delete_at`) VALUES -('1','system','系统','-','system','内部系统','系统自动注册的API',0,1,unix_timestamp(NOW())*1000,unix_timestamp(NOW())*1000,NULL), -('1-0','system','系统','/system','poly','内部聚合','内部生成的聚合API',0,1,unix_timestamp(NOW())*1000,unix_timestamp(NOW())*1000,NULL), -('1-1','system','系统','/system','faas','函数服务','通过faas注册的API',0,1,unix_timestamp(NOW())*1000,unix_timestamp(NOW())*1000,NULL), -('1-2','system','系统','/system','app','app根目录','app根目录',0,1,unix_timestamp(NOW())*1000,unix_timestamp(NOW())*1000,NULL), -('1-3','system','系统','/system','form','表单模型','通过form注册的API',0,1,unix_timestamp(NOW())*1000,unix_timestamp(NOW())*1000,NULL); - -UPDATE `api_namespace` SET `sub_count`=0; -UPDATE `api_namespace` u, - (SELECT `parent`, COUNT(1) cnt FROM `api_namespace` GROUP BY `parent`) t -SET u.`sub_count`=t.`cnt` WHERE CONCAT(u.`parent`,'/',u.`namespace`)=t.`parent`; -UPDATE `api_namespace` u, - (SELECT `parent`, COUNT(1) cnt FROM `api_namespace` GROUP BY `parent`) t -SET u.`sub_count`=t.`cnt` WHERE CONCAT('/',u.`namespace`)=t.`parent`; - -REPLACE INTO `api_service`(`id`,`owner`,`owner_name`,`namespace`,`name`,`title`,`desc`,`access`,`active`,`schema`,`host`,`auth_type`,`authorize`,`create_at`,`update_at`,`delete_at`) VALUES -('1','system','系统','/system/app','form','表单','表单接口',0,1,'http','form:8080','system',NULL,UNIX_TIMESTAMP(NOW())*1000,UNIX_TIMESTAMP(NOW())*1000,NULL), -('2','system','系统','/system/app','faas','函数服务','函数服务',0,1,'http','localhost:9999','none',NULL,UNIX_TIMESTAMP(NOW())*1000,UNIX_TIMESTAMP(NOW())*1000,NULL); - -/*--------------------------------------------------------------------------------------------------------------------------*/ -DROP TABLE IF EXISTS `api_raw`; -CREATE TABLE `api_raw` ( - `id` VARCHAR(64) COMMENT 'unique id', - `owner` VARCHAR(64) COMMENT 'owner id', - `owner_name`VARCHAR(64) COMMENT 'owner name', - `namespace` VARCHAR(384) NOT NULL COMMENT 'belong full namespace, eg: /a/b/c', - `name` VARCHAR(64) NOT NULL COMMENT 'unique name', - `service` VARCHAR(512) NOT NULL COMMENT 'belong service full path, eg: /a/b/c/servicesX', - `title` VARCHAR(64) COMMENT 'alias of name, mutable', - `desc` TEXT, - `version` VARCHAR(32), - `path` VARCHAR(512) NOT NULL COMMENT 'relative path, eg: /api/foo/bar', - `url` VARCHAR(512) NOT NULL COMMENT 'full path, eg: https://api.xxx.com/api/foo/bar', - `action` VARCHAR(64) DEFAULT '' COMMENT 'action on path', - `method` VARCHAR(16) NOT NULL COMMENT 'method', - `content` TEXT, - `doc` TEXT COMMENT 'api doc', - - `access` INT(11) NOT NULL COMMENT 'privilege for public access, 1,2,4,8,16,32 CRUDGX', - `active` TINYINT DEFAULT 1 COMMENT '1 ok, 0 disable', - `valid` TINYINT DEFAULT 1 COMMENT '1 valid, 0 invalid', - - `schema` VARCHAR(16) NOT NULL COMMENT 'from service, http/https', - `host` VARCHAR(128) NOT NULL COMMENT 'eg: api.xxx.com:8080', - `auth_type` VARCHAR(32) NOT NULL COMMENT 'none/system/signature/cookie/oauth2...', - - `create_at` BIGINT(20) COMMENT 'create time', - `update_at` BIGINT(20) COMMENT 'update time', - `delete_at` BIGINT(20) COMMENT 'delete time', - UNIQUE KEY `idx_global_name` (`namespace`,`name`), - KEY `idx_service` (`service`), - PRIMARY KEY (`id`) -)ENGINE=INNODB DEFAULT CHARSET=utf8; - -/*--------------------------------------------------------------------------------------------------------------------------*/ -DROP TABLE IF EXISTS `api_poly`; -CREATE TABLE `api_poly` ( - `id` VARCHAR(64) COMMENT 'unique id', - `owner` VARCHAR(64) COMMENT 'owner id', - `owner_name`VARCHAR(64) COMMENT 'owner name', - `namespace` VARCHAR(384) NOT NULL COMMENT 'belong full namespace, eg: /a/b/c', - `name` VARCHAR(64) NOT NULL COMMENT 'name', - `title` VARCHAR(64) COMMENT 'alias of name, mutable', - `desc` TEXT, - - `access` INT(11) NOT NULL COMMENT 'privilege for public access, 1,2,4,8,16,32 CRUDGX', - `active` TINYINT DEFAULT 1 COMMENT '1 ok, 0 disable', - `valid` TINYINT DEFAULT 1 COMMENT '1 valid, 0 invalid', - - `method` VARCHAR(16) NOT NULL COMMENT 'method', - `arrange` TEXT, - `doc` TEXT COMMENT 'api doc', - `script` TEXT, - - `create_at` BIGINT(20) COMMENT 'create time', - `update_at` BIGINT(20) COMMENT 'update time', - `build_at` BIGINT(20) COMMENT 'build time', - `delete_at` BIGINT(20) COMMENT 'delete time', - UNIQUE KEY `idx_global_name` (`namespace`,`name`), - PRIMARY KEY (`id`) -)ENGINE=INNODB DEFAULT CHARSET=utf8; - -/*--------------------------------------------------------------------------------------------------------------------------*/ -DROP TABLE IF EXISTS `api_permit_group`; -CREATE TABLE `api_permit_group` ( - `id` VARCHAR(64) COMMENT 'unique id', - `owner` VARCHAR(64) COMMENT 'owner id', - `owner_name`VARCHAR(64) COMMENT 'owner name', - `namespace` VARCHAR(384) NOT NULL COMMENT 'belong namespace', - `name` VARCHAR(64) NOT NULL COMMENT 'permit group name', - `title` VARCHAR(64) COMMENT 'alias, mutable', - `desc` TEXT, - - `access` INT(11) NOT NULL COMMENT 'privilege for public access, 1,2,4,8,16,32 CRUDGX', - `active` TINYINT DEFAULT 1 COMMENT '1 ok, 0 disable', - - `create_at` BIGINT(20) COMMENT 'create time', - `update_at` BIGINT(20) COMMENT 'update time', - `delete_at` BIGINT(20) COMMENT 'delete time', - UNIQUE KEY `idx_global_name` (`namespace`,`name`), - PRIMARY KEY (`id`) -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - -/*--------------------------------------------------------------------------------------------------------------------------*/ -DROP TABLE IF EXISTS `api_permit_elem`; -CREATE TABLE `api_permit_elem` ( - `id` VARCHAR(64) COMMENT 'unique id', - `owner` VARCHAR(64) COMMENT 'owner id', - `owner_name`VARCHAR(64) COMMENT 'owner name', - - `group_path` VARCHAR(448) COMMENT 'permitgroup path', - `elem_type` VARCHAR(10) COMMENT 'raw/poly/ckey/ns/service', - `elem_id` VARCHAR(64) COMMENT 'element id', - `elem_path` VARCHAR(512) COMMENT 'element path', - `desc` TEXT, - `elem_pri` INT(11) NOT NULL COMMENT 'privilege for this elem, 1,2,4,8,16,32 CRUDGX', - `content` TEXT COMMENT 'permission detail JSON, for api field control', - `active` TINYINT DEFAULT 1 COMMENT '1 ok, 0 disable', - - `create_at` BIGINT(20) COMMENT 'create time', - `update_at` BIGINT(20) COMMENT 'update time', - `delete_at` BIGINT(20) COMMENT 'delete time', - UNIQUE KEY `idx_group_elem` (`group_path`,`elem_type`, `elem_id`), - PRIMARY KEY (`id`) -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - -/*--------------------------------------------------------------------------------------------------------------------------*/ -DROP TABLE IF EXISTS `api_permit_grant`; -CREATE TABLE `api_permit_grant` ( - `id` VARCHAR(64) COMMENT 'unique id', - `owner` VARCHAR(64) COMMENT 'owner id', - `owner_name` VARCHAR(64) COMMENT 'owner name', - - `group_path` VARCHAR(448) COMMENT 'permitgroup path', - `grant_type` VARCHAR(10) COMMENT 'app/user/key/usergroup', - `grant_id` VARCHAR(64) COMMENT 'element id', - `grant_name` VARCHAR(64) COMMENT 'element name', - `grant_pri` INT(11) NOT NULL COMMENT 'privilege for this group, 1,2,4,8,16,32 CRUDGX', - `desc` TEXT, - `active` TINYINT DEFAULT 1 COMMENT '1 ok, 0 disable', - - `create_at` BIGINT(20) COMMENT 'create time', - `update_at` BIGINT(20) COMMENT 'update time', - `delete_at` BIGINT(20) COMMENT 'delete time', - UNIQUE KEY `idx_group_grant` (`group_path`, `grant_type`, `grant_id`), - KEY `idx_grant`(`grant_type`, `grant_id`), - PRIMARY KEY (`id`) -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - -DROP TABLE IF EXISTS `api_permit_group`; -DROP TABLE IF EXISTS `api_permit_elem`; -DROP TABLE IF EXISTS `api_permit_grant`; - -/*--------------------------------------------------------------------------------------------------------------------------*/ -DROP TABLE IF EXISTS `api_raw_poly`; -Create TABLE `api_raw_poly` ( - `id` VARCHAR(64) NOT NULL COMMENT 'unique id', - `raw_api` VARCHAR(512) NOT NULL COMMENT 'raw api full-path, eg: /a/b/c/rawApiName', - `poly_api` VARCHAR(512) NOT NULL COMMENT 'poly api full-path, eg: /a/b/c/polyApiName', - `delete_at` BIGINT(20) COMMENT 'delete time', - INDEX `idx_rawapi` (`raw_api`), - INDEX `idx_polyapi` (`poly_api`), - PRIMARY KEY (`id`) -)ENGINE=InnoDB DEFAULT CHARSET=utf8; - -/*--------------------------------------------------------------------------------------------------------------------------*/ -DROP TABLE IF EXISTS `api_schema`; -CREATE TABLE `api_schema` ( - `ID` VARCHAR(64) COMMENT 'unique id', - `namespace` VARCHAR(384) NOT NULL COMMENT 'belong full namespace, eg: /a/b/c', - `name` VARCHAR(64) NOT NULL COMMENT 'unique name', - `title` VARCHAR(64) COMMENT 'alias of name', - `desc` TEXT, - `schema` TEXT NOT NULL COMMENT 'api schema', - `create_at` BIGINT(20) COMMENT 'create time', - `update_at` BIGINT(20) COMMENT 'update time', - `delete_at` BIGINT(20) COMMENT 'delete time', - UNIQUE KEY `idx_global_name` (`namespace`, `name`), - PRIMARY KEY (`id`) -)ENGINE=INNODB DEFAULT CHARSET=utf8; - -DROP TABLE IF EXISTS `api_permit_group`; -DROP TABLE IF EXISTS `api_permit_elem`; -DROP TABLE IF EXISTS `api_permit_grant`; - - - -/*Data for the table `api_poly` */ - -REPLACE INTO `api_poly`(`id`,`owner`,`owner_name`,`namespace`,`name`,`title`,`desc`,`access`,`active`,`valid`,`method`,`arrange`,`doc`,`script`,`create_at`,`update_at`,`build_at`,`delete_at`) VALUES -('poly_AAxfxhEZG2epwoUU1cmAYIKZGyq_xFs3llI4eJcXKMVG','system','系统','/system/poly','permissionInit.p','应用初始化','',0,1,1,'POST','{}','{}','// polyTmpScript_/system/poly/permissionInit.p_2022-03-24T16:43:24CST\nvar _tmp = function(){\n var d = { \"__input\": __input, } // qyAllLocalData\n\n d.start = __input.body\n\n d.start.header = d.start.header || {}\n d.start._ = [\n pdCreateNS(\'/system/app\',d.start.appID,\'应用\'),\n pdCreateNS(\'/system/app/\'+d.start.appID,\'poly\',\'API编排\'),\n pdCreateNS(\'/system/app/\'+d.start.appID,\'raw\',\'原生API\'),\n pdCreateNS(\'/system/app/\'+d.start.appID+\'/raw\',\'faas\',\'函数服务\'),\n pdCreateNS(\'/system/app/\'+d.start.appID+\'/raw\',\'customer\',\'代理第三方API\'),\n pdCreateNS(\'/system/app/\'+d.start.appID+\'/raw/customer\',\'default\',\'默认分组\'),\n pdCreateNS(\'/system/app/\'+d.start.appID+\'/raw\',\'inner\',\'平台API\'),\n pdCreateNS(\'/system/app/\'+d.start.appID+\'/raw/inner\',\'form\',\'表单模型API\'),\n ]\n if (true) { // req1, create\n var _apiPath = format(\"http://structor/api/v1/structor/%v/base/permission/perGroup/create\" ,d.start.appID)\n var _t = {\n \"name\": d.start.name,\n \"description\": d.start.description,\n \"types\": d.start.types,\n }\n var _th = pdNewHttpHeader()\n pdAddHttpHeader(_th, \"Content-Type\", \"application/json\")\n\n var _tk = \'\';\n var _tb = pdAppendAuth(_tk, \'none\', _th, pdToJson(_t))\n d.req1 = pdToJsobj(\"json\", pdHttpRequest(_apiPath, \"POST\", _tb, _th, pdQueryUser(true)))\n }\n d.cond1 = { y: false, }\n if (d.req1.code==0) {\n d.cond1.y = true\n if (true) { // req2, update\n var _apiPath = format(\"http://structor/api/v1/structor/%v/base/permission/perGroup/update\" ,d.start.appID)\n var _t = {\n \"id\": d.req1.data.id,\n \"scopes\": d.start.scopes,\n }\n var _th = pdNewHttpHeader()\n pdAddHttpHeader(_th, \"Content-Type\", \"application/json\")\n\n var _tk = \'\';\n var _tb = pdAppendAuth(_tk, \'none\', _th, pdToJson(_t))\n d.req2 = pdToJsobj(\"json\", pdHttpRequest(_apiPath, \"POST\", _tb, _th, pdQueryUser(true)))\n }\n }\n\n d.end = {\n \"createNamespaces\": d.start._,\n \"req1\": d.req1,\n \"req2\": sel(d.cond1.y,d.req2,undefined),\n }\n return pdToJsonP(d.end)\n}; _tmp();\n',1648111401543,1648111406872,1648111408942,NULL); - -/*Data for the table `api_raw` */ - -REPLACE INTO `api_raw`(`id`,`owner`,`owner_name`,`namespace`,`name`,`service`,`title`,`desc`,`version`,`path`,`url`,`action`,`method`,`content`,`doc`,`access`,`active`,`valid`,`schema`,`host`,`auth_type`,`create_at`,`update_at`,`delete_at`) VALUES -('raw_AAAxYvGEh8iIgpjBqleBRjS2J_XKkYJ9IeXyGU9xAt0R','system','系统','/system/form','base_pergroup_create.r','','创建用户组','','last','/api/v1/structor/:appID/base/permission/perGroup/create','http://structor/api/v1/structor/:appID/base/permission/perGroup/create','','POST','{\"x-id\":\"raw_AAAxYvGEh8iIgpjBqleBRjS2J_XKkYJ9IeXyGU9xAt0R\",\"x-action\":\"\",\"x-consts\":[],\"x-input\":{},\"x-output\":{\"body\":{\"type\":\"\",\"name\":\"\",\"data\":null}},\"basePath\":\"/\",\"path\":\"/api/v1/structor/:appID/base/permission/perGroup/create\",\"method\":\"POST\",\"encoding-in\":\"json\",\"encoding-out\":\"json\",\"summary\":\"创建用户组\",\"desc\":\"\"}','{\"x-id\":\"\",\"version\":\"v0.7.3(2021-12-29@f6d9b2b)\",\"x-fmt-inout\":{\"method\":\"POST\",\"url\":\"/api/v1/polyapi/request/system/form/base_pergroup_create.r\",\"input\":{\"inputs\":[{\"type\":\"string\",\"name\":\"X-Polysign-Access-Key-Id\",\"title\":\"签名密钥序号\",\"desc\":\"access_key_id dispatched by poly api server\",\"$appendix$\":true,\"data\":\"KeiIY8098435rty\",\"in\":\"header\",\"mock\":\"KeiIY8098435rty\"},{\"type\":\"string\",\"name\":\"X-Polysign-Timestamp\",\"title\":\"签名时间戳\",\"desc\":\"timestamp format ISO8601: 2006-01-02T15:04:05-0700\",\"$appendix$\":true,\"data\":\"2020-12-31T12:34:56+0800\",\"in\":\"header\",\"mock\":\"2020-12-31T12:34:56+0800\"},{\"type\":\"string\",\"name\":\"X-Polysign-Version\",\"title\":\"签名版本\",\"desc\":\"\\\"1\\\" only current\",\"$appendix$\":true,\"data\":\"1\",\"in\":\"header\",\"mock\":\"1\"},{\"type\":\"string\",\"name\":\"X-Polysign-Method\",\"title\":\"签名方法\",\"desc\":\"\\\"HmacSHA256\\\" only current\",\"$appendix$\":true,\"data\":\"HmacSHA256\",\"in\":\"header\",\"mock\":\"HmacSHA256\"},{\"type\":\"string\",\"name\":\"Access-Token\",\"title\":\"登录授权码\",\"desc\":\"Access-Token from oauth2 if use token access mode\",\"$appendix$\":true,\"data\":null,\"in\":\"header\",\"mock\":\"H3K56789lHIUkjfkslds\"},{\"type\":\"string\",\"name\":\"appID\",\"required\":true,\"data\":null,\"in\":\"path\"},{\"type\":\"object\",\"name\":\"root\",\"data\":[{\"type\":\"string\",\"name\":\"name\",\"data\":null},{\"type\":\"string\",\"name\":\"description\",\"data\":null},{\"type\":\"string\",\"name\":\"x_polyapi_signature\",\"title\":\"参数签名\",\"desc\":\"required if Access-Token doesn\'t use.\\nHmacSHA256 signature of input body: sort query gonic asc|sha256 \\u003cSECRET_KEY\\u003e|base64 std encode\",\"$appendix$\":true,\"data\":\"EJML8aQ3BkbciPwMYHlffv2BagW0kdoI3L_qOedQylw\"},{\"type\":\"object\",\"name\":\"$polyapi_hide$\",\"title\":\"隐藏参数\",\"desc\":\"polyapi reserved hide args like path args in raw api.\",\"$appendix$\":true,\"data\":[]}],\"in\":\"body\"}]},\"output\":{\"body\":{\"type\":\"\",\"name\":\"\",\"data\":null},\"doc\":[{\"type\":\"object\",\"desc\":\"successful operation\",\"data\":[{\"type\":\"string\",\"name\":\"msg\",\"data\":null},{\"type\":\"number\",\"name\":\"code\",\"data\":null},{\"type\":\"object\",\"name\":\"data\",\"data\":[{\"type\":\"string\",\"name\":\"id\",\"desc\":\"新增后,权限用户组id\",\"data\":null}]}],\"in\":\"body\"}]},\"sampleInput\":[{\"header\":{\"Access-Token\":[\"H3K56789lHIUkjfkslds\"],\"X-Polysign-Access-Key-Id\":[\"KeiIY8098435rty\"],\"X-Polysign-Method\":[\"HmacSHA256\"],\"X-Polysign-Timestamp\":[\"2020-12-31T12:34:56+0800\"],\"X-Polysign-Version\":[\"1\"]},\"body\":{\"$polyapi_hide$\":{\"appID\":\"4x\"},\"description\":\"vYc\",\"name\":\"zxR\",\"x_polyapi_signature\":\"EJML8aQ3BkbciPwMYHlffv2BagW0kdoI3L_qOedQylw\"}},{\"header\":{\"登录授权码\":[\"H3K56789lHIUkjfkslds\"],\"签名密钥序号\":[\"KeiIY8098435rty\"],\"签名方法\":[\"HmacSHA256\"],\"签名时间戳\":[\"2020-12-31T12:34:56+0800\"],\"签名版本\":[\"1\"]},\"body\":{\"description\":\"u_vOjzgB\",\"name\":\"Kk4L0opORX\",\"参数签名\":\"EJML8aQ3BkbciPwMYHlffv2BagW0kdoI3L_qOedQylw\",\"隐藏参数\":{\"appID\":\"ovK-GRJ28N\"}}}],\"sampleOutput\":[{\"resp\":{\"code\":17,\"data\":{\"id\":\"t8\"},\"msg\":\"xW4\"}},{\"resp\":{\"code\":4,\"data\":{\"id\":\"8u9sOoVCP\"},\"msg\":\"fYSmb134qiG\"}}]},\"x-swagger\":{\"x-consts\":null,\"host\":\"structor\",\"swagger\":\"2.0\",\"info\":{\"title\":\"\",\"version\":\"last\",\"description\":\"auto generated\",\"contact\":{\"name\":\"\",\"url\":\"\",\"email\":\"\"}},\"schemes\":[\"http\"],\"basePath\":\"/\",\"paths\":{\"/api/v1/structor/:appID/base/permission/perGroup/create\":{\"post\":{\"x-consts\":[],\"operationId\":\"base_pergroup_create\",\"parameters\":[{\"name\":\"appID\",\"in\":\"path\",\"description\":\"\",\"required\":true,\"type\":\"string\"},{\"name\":\"root\",\"in\":\"body\",\"schema\":{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"type\":\"object\",\"properties\":{\"name\":{\"type\":\"string\"},\"description\":{\"type\":\"string\"}},\"required\":[]}}],\"responses\":{\"200\":{\"description\":\"successful operation\",\"schema\":{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"number\"},\"data\":{\"type\":\"object\",\"properties\":{\"id\":{\"type\":\"string\",\"description\":\"新增后,权限用户组id\"}}},\"msg\":{\"type\":\"string\"}},\"required\":[\"code\"]}}},\"consumes\":[\"application/json\"],\"produces\":[\"application/json\"],\"summary\":\"创建用户组\",\"description\":\"\"}}}}}',0,1,1,'http','structor','none',1648111398882,1648111398882,NULL), -('raw_AM51O-2rUXb1RVDXnOvAo8FRq5BJzaO4vdO8QVx-qZ1n','system','系统','/system/form','base_pergroup_update.r','','给用户组加入人员或者部门','','last','/api/v1/structor/:appID/base/permission/perGroup/update','http://structor/api/v1/structor/:appID/base/permission/perGroup/update','','POST','{\"x-id\":\"raw_AM51O-2rUXb1RVDXnOvAo8FRq5BJzaO4vdO8QVx-qZ1n\",\"x-action\":\"\",\"x-consts\":[],\"x-input\":{},\"x-output\":{\"body\":{\"type\":\"\",\"name\":\"\",\"data\":null}},\"basePath\":\"/\",\"path\":\"/api/v1/structor/:appID/base/permission/perGroup/update\",\"method\":\"POST\",\"encoding-in\":\"json\",\"encoding-out\":\"json\",\"summary\":\"给用户组加入人员或者部门\",\"desc\":\"\"}','{\"x-id\":\"\",\"version\":\"v0.7.3(2021-12-29@f6d9b2b)\",\"x-fmt-inout\":{\"method\":\"POST\",\"url\":\"/api/v1/polyapi/request/system/form/base_pergroup_update.r\",\"input\":{\"inputs\":[{\"type\":\"string\",\"name\":\"X-Polysign-Access-Key-Id\",\"title\":\"签名密钥序号\",\"desc\":\"access_key_id dispatched by poly api server\",\"$appendix$\":true,\"data\":\"KeiIY8098435rty\",\"in\":\"header\",\"mock\":\"KeiIY8098435rty\"},{\"type\":\"string\",\"name\":\"X-Polysign-Timestamp\",\"title\":\"签名时间戳\",\"desc\":\"timestamp format ISO8601: 2006-01-02T15:04:05-0700\",\"$appendix$\":true,\"data\":\"2020-12-31T12:34:56+0800\",\"in\":\"header\",\"mock\":\"2020-12-31T12:34:56+0800\"},{\"type\":\"string\",\"name\":\"X-Polysign-Version\",\"title\":\"签名版本\",\"desc\":\"\\\"1\\\" only current\",\"$appendix$\":true,\"data\":\"1\",\"in\":\"header\",\"mock\":\"1\"},{\"type\":\"string\",\"name\":\"X-Polysign-Method\",\"title\":\"签名方法\",\"desc\":\"\\\"HmacSHA256\\\" only current\",\"$appendix$\":true,\"data\":\"HmacSHA256\",\"in\":\"header\",\"mock\":\"HmacSHA256\"},{\"type\":\"string\",\"name\":\"Access-Token\",\"title\":\"登录授权码\",\"desc\":\"Access-Token from oauth2 if use token access mode\",\"$appendix$\":true,\"data\":null,\"in\":\"header\",\"mock\":\"H3K56789lHIUkjfkslds\"},{\"type\":\"string\",\"name\":\"appID\",\"required\":true,\"data\":null,\"in\":\"path\"},{\"type\":\"object\",\"name\":\"root\",\"title\":\"empty object\",\"data\":[{\"type\":\"string\",\"name\":\"id\",\"desc\":\"用户组权限id\",\"data\":null},{\"type\":\"array\",\"name\":\"scopes\",\"data\":[{\"type\":\"object\",\"name\":\"\",\"data\":[{\"type\":\"number\",\"name\":\"type\",\"desc\":\"1 人员 2 部门\",\"data\":null},{\"type\":\"string\",\"name\":\"id\",\"desc\":\"人员或者部门id\",\"data\":null},{\"type\":\"string\",\"name\":\"name\",\"desc\":\"人员或者部门名字\",\"data\":null}]}]},{\"type\":\"string\",\"name\":\"x_polyapi_signature\",\"title\":\"参数签名\",\"desc\":\"required if Access-Token doesn\'t use.\\nHmacSHA256 signature of input body: sort query gonic asc|sha256 \\u003cSECRET_KEY\\u003e|base64 std encode\",\"$appendix$\":true,\"data\":\"EJML8aQ3BkbciPwMYHlffv2BagW0kdoI3L_qOedQylw\"},{\"type\":\"object\",\"name\":\"$polyapi_hide$\",\"title\":\"隐藏参数\",\"desc\":\"polyapi reserved hide args like path args in raw api.\",\"$appendix$\":true,\"data\":[]}],\"in\":\"body\"}]},\"output\":{\"body\":{\"type\":\"\",\"name\":\"\",\"data\":null},\"doc\":[{\"type\":\"object\",\"desc\":\"successful operation\",\"data\":[{\"type\":\"object\",\"name\":\"data\",\"data\":[]},{\"type\":\"string\",\"name\":\"msg\",\"data\":null},{\"type\":\"number\",\"name\":\"code\",\"data\":null}],\"in\":\"body\"}]},\"sampleInput\":[{\"header\":{\"Access-Token\":[\"H3K56789lHIUkjfkslds\"],\"X-Polysign-Access-Key-Id\":[\"KeiIY8098435rty\"],\"X-Polysign-Method\":[\"HmacSHA256\"],\"X-Polysign-Timestamp\":[\"2020-12-31T12:34:56+0800\"],\"X-Polysign-Version\":[\"1\"]},\"body\":{\"$polyapi_hide$\":{\"appID\":\"z4YpHB\"},\"id\":\"Ing5IkP2\",\"scopes\":[{\"id\":\"cEDmW\",\"name\":\"vd4cGe2JAl\",\"type\":15}],\"x_polyapi_signature\":\"EJML8aQ3BkbciPwMYHlffv2BagW0kdoI3L_qOedQylw\"}},{\"header\":{\"登录授权码\":[\"H3K56789lHIUkjfkslds\"],\"签名密钥序号\":[\"KeiIY8098435rty\"],\"签名方法\":[\"HmacSHA256\"],\"签名时间戳\":[\"2020-12-31T12:34:56+0800\"],\"签名版本\":[\"1\"]},\"body\":{\"id\":\"x010u\",\"scopes\":[{\"id\":\"Kp3\",\"name\":\"3tBMriHYO\",\"type\":16}],\"参数签名\":\"EJML8aQ3BkbciPwMYHlffv2BagW0kdoI3L_qOedQylw\",\"隐藏参数\":{\"appID\":\"pfi\"}}}],\"sampleOutput\":[{\"resp\":{\"code\":10,\"data\":{},\"msg\":\"aEK\"}},{\"resp\":{\"code\":9,\"data\":{},\"msg\":\"ZlHhTVQRIE\"}}]},\"x-swagger\":{\"x-consts\":null,\"host\":\"structor\",\"swagger\":\"2.0\",\"info\":{\"title\":\"\",\"version\":\"last\",\"description\":\"auto generated\",\"contact\":{\"name\":\"\",\"url\":\"\",\"email\":\"\"}},\"schemes\":[\"http\"],\"basePath\":\"/\",\"paths\":{\"/api/v1/structor/:appID/base/permission/perGroup/update\":{\"post\":{\"x-consts\":[],\"operationId\":\"base_pergroup_update\",\"parameters\":[{\"name\":\"appID\",\"in\":\"path\",\"description\":\"\",\"required\":true,\"type\":\"string\"},{\"name\":\"root\",\"in\":\"body\",\"schema\":{\"type\":\"object\",\"title\":\"empty object\",\"properties\":{\"id\":{\"type\":\"string\",\"description\":\"用户组权限id\"},\"scopes\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"type\":{\"type\":\"integer\",\"description\":\"1 人员 2 部门\"},\"id\":{\"type\":\"string\",\"description\":\"人员或者部门id\"},\"name\":{\"type\":\"string\",\"description\":\"人员或者部门名字\"}},\"required\":[\"type\",\"id\",\"name\"]}}},\"required\":[\"id\",\"scopes\"]}}],\"responses\":{\"200\":{\"description\":\"successful operation\",\"schema\":{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"number\"},\"data\":{\"type\":\"object\",\"properties\":{}},\"msg\":{\"type\":\"string\"}}}}},\"consumes\":[\"application/json\"],\"produces\":[\"application/json\"],\"summary\":\"给用户组加入人员或者部门\",\"description\":\"\"}}}}}',0,1,1,'http','structor','none',1648111400071,1648111400071,NULL); - - -REPLACE INTO `api_service`(`id`,`owner`,`owner_name`,`namespace`,`name`,`title`,`desc`,`access`,`active`,`schema`,`host`,`auth_type`,`authorize`,`create_at`,`update_at`,`delete_at`) VALUES -('1','system','系统','/system/app','form','表单','表单接口',0,1,'http','form:8080','system',NULL,UNIX_TIMESTAMP(NOW())*1000,UNIX_TIMESTAMP(NOW())*1000,NULL), -('2','system','系统','/system/app','faas','函数服务','函数服务',0,1,'http','localhost:9999','none',NULL,UNIX_TIMESTAMP(NOW())*1000,UNIX_TIMESTAMP(NOW())*1000,NULL); - -DROP TABLE IF EXISTS `api_permit_group`; -DROP TABLE IF EXISTS `api_permit_elem`; -DROP TABLE IF EXISTS `api_permit_grant`; - -DELETE FROM `api_raw` WHERE `namespace`='/system/faas'; -DELETE FROM `api_namespace` WHERE `parent` LIKE '%/raw/inner/form'; - -INSERT INTO `api_namespace`(`id`,`owner`,`owner_name`,`parent`,`namespace`,`title`,`desc`,`access`,`active`,`create_at`,`update_at`,`delete_at`) -SELECT DISTINCT MD5(CONCAT(SUBSTR(`namespace`,1,CHAR_LENGTH('/system/app/bmrmk/raw/inner/form')),SUBSTR(`name`,1,INSTR(`name`,'_')-1))),`owner`,'',SUBSTR(`namespace`,1,CHAR_LENGTH('/system/app/bmrmk/raw/inner/form')),SUBSTR(`name`,1,INSTR(`name`,'_')-1), -SUBSTR(`title`,1,INSTR(`title`,'(')-1),'',0,1,UNIX_TIMESTAMP(NOW())*1000,UNIX_TIMESTAMP(NOW())*1000,NULL FROM api_raw WHERE service='/system/app/form'; - -DROP TABLE IF EXISTS `tt`; -CREATE TABLE `tt` ( - `id` VARCHAR(64) -)ENGINE=INNODB DEFAULT CHARSET=utf8; -INSERT INTO tt(`id`) SELECT s.`id` FROM `api_raw` s INNER JOIN `api_raw` t WHERE s.`namespace` LIKE '%/inner/form/custom' AND t.`namespace` LIKE '%/inner/form/form' -AND s.`name`=t.`name` AND SUBSTR(s.`namespace`,1,CHAR_LENGTH('/system/app/bmrmk/raw/inner/form/'))=SUBSTR(t.`namespace`,1,CHAR_LENGTH('/system/app/bmrmk/raw/inner/form/')); -DELETE FROM `api_raw` WHERE `id` IN (SELECT id FROM `tt`); -DROP TABLE IF EXISTS `tt`; -UPDATE `api_raw` SET `namespace`=CONCAT(SUBSTR(`namespace`,1,CHAR_LENGTH('/system/app/bmrmk/raw/inner/form/')),SUBSTR(`name`,1,INSTR(`name`,'_')-1)) WHERE service='/system/app/form'; - -DELIMITER $$ -DROP PROCEDURE IF EXISTS `fix_app_path` $$ -CREATE PROCEDURE fix_app_path() -BEGIN - DECLARE app_id VARCHAR(255); - DECLARE tm DATETIME; - DECLARE sid INT; - DECLARE done INT DEFAULT FALSE; - DECLARE cur_app CURSOR FOR SELECT `namespace` FROM api_namespace WHERE `parent` = '/system/app'; - DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; - - SET tm=NOW(); - SET sid=1; - OPEN cur_app; - app_loop: LOOP - FETCH cur_app INTO app_id; - IF done THEN - LEAVE app_loop; - END IF; - REPLACE INTO `api_namespace`(`id`,`owner`,`owner_name`,`parent`,`namespace`,`title`,`desc`,`access`,`active`,`create_at`,`update_at`,`delete_at`) VALUES - (CONCAT(tm,'_',sid),'system','系统',CONCAT('/system/app/',app_id,'/raw'),'faas','函数服务','函数服务',0,1,UNIX_TIMESTAMP(NOW())*1000,UNIX_TIMESTAMP(NOW())*1000,NULL); - SET sid=sid+1; - END LOOP app_loop; - CLOSE cur_app; - -END; -$$ -DELIMITER ; -CALL fix_app_path(); -DROP PROCEDURE IF EXISTS `fix_app_path`; diff --git a/deployment/deployment/schemas/process.sql b/deployment/deployment/schemas/process.sql deleted file mode 100644 index 6478ea8..0000000 --- a/deployment/deployment/schemas/process.sql +++ /dev/null @@ -1,259 +0,0 @@ -/* - Navicat Premium Data Transfer - - Source Server : staging - Source Server Type : MySQL - Source Server Version : 50729 - Source Host : 192.168.208.253:3306 - Source Schema : process - - Target Server Type : MySQL - Target Server Version : 50729 - File Encoding : 65001 - - Date: 26/10/2021 16:02:05 -*/ - -CREATE DATABASE process; -USE process; - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - --- ---------------------------- --- Table structure for proc_execution --- ---------------------------- -DROP TABLE IF EXISTS `proc_execution`; -CREATE TABLE `proc_execution` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT 'id', - `proc_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程id', - `proc_instance_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程实例id', - `p_id` varchar(40) NOT NULL DEFAULT '' COMMENT '父id', - `node_def_key` varchar(120) NOT NULL DEFAULT '' COMMENT '节点自定义key', - `node_instance_id` varchar(40) NOT NULL DEFAULT '' COMMENT '节点实例id', - `is_active` tinyint(1) NOT NULL DEFAULT '1' COMMENT '激活状态', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人id', - `create_time` varchar(40) NOT NULL DEFAULT '' COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人id', - `modify_time` varchar(40) NOT NULL DEFAULT '' COMMENT '更新时间', - `tenant_id` varchar(40) NOT NULL DEFAULT '' COMMENT '租户id', - PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='流程执行实例分析'; - --- ---------------------------- --- Table structure for proc_history_task --- ---------------------------- -DROP TABLE IF EXISTS `proc_history_task`; -CREATE TABLE `proc_history_task` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT 'id', - `proc_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程id', - `proc_instance_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程实例id', - `execution_id` varchar(40) NOT NULL DEFAULT '' COMMENT '执行id', - `node_id` varchar(40) NOT NULL DEFAULT '' COMMENT '节点id', - `node_def_key` varchar(120) NOT NULL DEFAULT '' COMMENT '节点自定义key', - `next_node_def_key` varchar(120) NOT NULL COMMENT '下个节点的自定义key', - `name` varchar(100) NOT NULL DEFAULT '' COMMENT '任务名称', - `desc` varchar(100) NOT NULL DEFAULT '' COMMENT '描述', - `assignee` varchar(36) NOT NULL DEFAULT '' COMMENT '处理人', - `task_type` varchar(100) NOT NULL DEFAULT 'Model' COMMENT 'Model模型任务、TempModel临时模型任务、NonModel非模型任务', - `status` varchar(40) NOT NULL DEFAULT '' COMMENT '状态', - `due_time` varchar(40) NOT NULL DEFAULT '0' COMMENT '有效时间', - `end_time` varchar(40) NOT NULL DEFAULT '0' COMMENT '结束时间', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人id', - `create_time` varchar(40) NOT NULL DEFAULT '' COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人id', - `modify_time` varchar(40) NOT NULL DEFAULT '' COMMENT '更新时间', - `tenant_id` varchar(40) NOT NULL DEFAULT '' COMMENT '租户id', - PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='流程历史任务'; - --- ---------------------------- --- Table structure for proc_identity_link --- ---------------------------- -DROP TABLE IF EXISTS `proc_identity_link`; -CREATE TABLE `proc_identity_link` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT 'id', - `node_id` varchar(40) NOT NULL DEFAULT '' COMMENT '节点id', - `identity_type` varchar(20) NOT NULL DEFAULT '' COMMENT '类型', - `user_id` varchar(40) NOT NULL DEFAULT '' COMMENT '用户id', - `group_id` varchar(40) NOT NULL DEFAULT '' COMMENT '组id', - `variable` varchar(100) NOT NULL DEFAULT '' COMMENT '变量名', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人id', - `create_time` varchar(40) NOT NULL DEFAULT '' COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人id', - `modify_time` varchar(40) NOT NULL DEFAULT '' COMMENT '更新时间', - `tenant_id` varchar(40) NOT NULL DEFAULT '' COMMENT '租户id', - PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='流程处理人关联'; - --- ---------------------------- --- Table structure for proc_instance --- ---------------------------- -DROP TABLE IF EXISTS `proc_instance`; -CREATE TABLE `proc_instance` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT 'id', - `proc_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程id', - `name` varchar(100) NOT NULL DEFAULT '' COMMENT '流程实例名称', - `p_id` varchar(40) NOT NULL DEFAULT '' COMMENT '父级流程实例id', - `status` varchar(100) NOT NULL DEFAULT '' COMMENT '状态', - `end_time` varchar(40) NOT NULL DEFAULT '' COMMENT '流程实例结束时间', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人id', - `create_time` varchar(40) NOT NULL DEFAULT '' COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人id', - `modify_time` varchar(40) NOT NULL DEFAULT '' COMMENT '更新时间', - `tenant_id` varchar(40) NOT NULL DEFAULT '' COMMENT '租户id', - PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='流程实例'; - --- ---------------------------- --- Table structure for proc_model --- ---------------------------- -DROP TABLE IF EXISTS `proc_model`; -CREATE TABLE `proc_model` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT 'id', - `name` varchar(100) NOT NULL DEFAULT '' COMMENT '流程名称', - `def_key` varchar(100) NOT NULL DEFAULT '' COMMENT '流程自定义key', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人id', - `create_time` varchar(40) NOT NULL DEFAULT '' COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人id', - `modify_time` varchar(40) NOT NULL DEFAULT '' COMMENT '更新时间', - `tenant_id` varchar(40) NOT NULL DEFAULT '' COMMENT '租户id', - PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='流程模型'; - --- ---------------------------- --- Table structure for proc_node --- ---------------------------- -DROP TABLE IF EXISTS `proc_node`; -CREATE TABLE `proc_node` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT 'id', - `proc_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程id', - `proc_instance_id` varchar(40) DEFAULT NULL COMMENT '加签临时节点的实例id', - `name` varchar(100) NOT NULL DEFAULT '' COMMENT '流程名称', - `def_key` varchar(120) NOT NULL DEFAULT '' COMMENT '节点自定义key', - `node_type` varchar(20) NOT NULL DEFAULT '' COMMENT '节点类型', - `pair_def_key` varchar(120) NOT NULL COMMENT '分流节点对应的合流节点', - `sub_proc_id` varchar(40) NOT NULL DEFAULT '' COMMENT '子流程id', - `desc` varchar(100) NOT NULL DEFAULT '' COMMENT '描述', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人id', - `create_time` varchar(40) NOT NULL DEFAULT '' COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人id', - `modify_time` varchar(40) NOT NULL DEFAULT '' COMMENT '更新时间', - `tenant_id` varchar(40) NOT NULL DEFAULT '' COMMENT '租户id', - PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='流程节点'; - --- ---------------------------- --- Table structure for proc_node_instance --- ---------------------------- -DROP TABLE IF EXISTS `proc_node_instance`; -CREATE TABLE `proc_node_instance` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT 'id', - `proc_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程id', - `proc_instance_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程实例id', - `p_id` varchar(40) NOT NULL DEFAULT '' COMMENT '父id', - `execution_id` varchar(40) NOT NULL DEFAULT '' COMMENT '执行id', - `node_def_key` varchar(120) NOT NULL DEFAULT '' COMMENT '节点自定义key', - `node_name` varchar(100) NOT NULL DEFAULT '' COMMENT '节点名称', - `node_type` varchar(20) NOT NULL DEFAULT '' COMMENT '节点类型', - `task_id` varchar(40) NOT NULL DEFAULT '' COMMENT '任务id', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人id', - `create_time` varchar(40) NOT NULL DEFAULT '' COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人id', - `modify_time` varchar(40) NOT NULL DEFAULT '' COMMENT '更新时间', - `tenant_id` varchar(40) NOT NULL DEFAULT '' COMMENT '租户id', - PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='节点实例'; - --- ---------------------------- --- Table structure for proc_node_link --- ---------------------------- -DROP TABLE IF EXISTS `proc_node_link`; -CREATE TABLE `proc_node_link` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT 'id', - `proc_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程id', - `node_id` varchar(40) NOT NULL DEFAULT '' COMMENT '节点id', - `next_node_def_key` varchar(120) NOT NULL DEFAULT '' COMMENT '下个节点自定义id', - `condition` varchar(2000) NOT NULL DEFAULT '' COMMENT '条件', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人id', - `create_time` varchar(40) NOT NULL DEFAULT '' COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人id', - `modify_time` varchar(40) NOT NULL DEFAULT '' COMMENT '更新时间', - `tenant_id` varchar(40) NOT NULL DEFAULT '' COMMENT '租户id', - PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='流程节点关联'; - --- ---------------------------- --- Table structure for proc_task --- ---------------------------- -DROP TABLE IF EXISTS `proc_task`; -CREATE TABLE `proc_task` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT 'id', - `proc_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程id', - `proc_instance_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程实例id', - `execution_id` varchar(40) NOT NULL DEFAULT '' COMMENT '执行id', - `node_id` varchar(40) NOT NULL DEFAULT '' COMMENT '节点id', - `node_def_key` varchar(120) NOT NULL DEFAULT '' COMMENT '节点自定义key', - `next_node_def_key` varchar(120) NOT NULL COMMENT '下个节点的自定义key', - `name` varchar(100) NOT NULL DEFAULT '' COMMENT '任务名称', - `desc` varchar(100) NOT NULL DEFAULT '' COMMENT '描述', - `assignee` varchar(36) NOT NULL DEFAULT '' COMMENT '处理人', - `task_type` varchar(100) NOT NULL DEFAULT 'Model' COMMENT 'Model模型任务、TempModel临时模型任务、NonModel非模型任务', - `status` varchar(40) NOT NULL DEFAULT '' COMMENT '状态', - `end_time` varchar(40) NOT NULL DEFAULT '' COMMENT '结束时间', - `due_time` varchar(40) NOT NULL DEFAULT '' COMMENT '有效时间', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人id', - `create_time` varchar(40) NOT NULL DEFAULT '' COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人id', - `modify_time` varchar(40) NOT NULL DEFAULT '' COMMENT '更新时间', - `tenant_id` varchar(40) NOT NULL DEFAULT '' COMMENT '租户id', - PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='流程任务实例'; - --- ---------------------------- --- Table structure for proc_task_identity --- ---------------------------- -DROP TABLE IF EXISTS `proc_task_identity`; -CREATE TABLE `proc_task_identity` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT 'id', - `instance_id` varchar(40) NOT NULL COMMENT '流程实例id', - `task_id` varchar(40) NOT NULL DEFAULT '' COMMENT '任务id', - `identity_type` varchar(20) NOT NULL DEFAULT '' COMMENT '类型', - `user_id` varchar(40) NOT NULL DEFAULT '' COMMENT '用户id', - `group_id` varchar(40) NOT NULL DEFAULT '' COMMENT '组id', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人id', - `create_time` varchar(40) NOT NULL DEFAULT '' COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人id', - `modify_time` varchar(40) NOT NULL DEFAULT '' COMMENT '更新时间', - `tenant_id` varchar(40) NOT NULL DEFAULT '' COMMENT '租户id' -) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='任务处理人'; - --- ---------------------------- --- Table structure for proc_variables --- ---------------------------- -DROP TABLE IF EXISTS `proc_variables`; -CREATE TABLE `proc_variables` ( - `id` varchar(40) NOT NULL DEFAULT '' COMMENT 'id', - `proc_instance_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程实例id', - `node_id` varchar(40) NOT NULL DEFAULT '' COMMENT '流程任务实例id', - `var_scope` varchar(100) NOT NULL DEFAULT '' COMMENT '变量作用范围', - `name` varchar(100) NOT NULL DEFAULT '' COMMENT '变量名称', - `var_type` varchar(100) NOT NULL DEFAULT '' COMMENT '类型', - `value` varchar(100) NOT NULL DEFAULT '' COMMENT '变量值', - `bytes_value` longblob COMMENT '存储序列化变量值', - `complex_value` json DEFAULT NULL COMMENT '存储复杂的变量值', - `creator_id` varchar(40) NOT NULL DEFAULT '' COMMENT '创建人id', - `create_time` varchar(40) NOT NULL DEFAULT '' COMMENT '创建时间', - `modifier_id` varchar(40) NOT NULL DEFAULT '' COMMENT '更新人id', - `modify_time` varchar(40) NOT NULL DEFAULT '' COMMENT '更新时间', - `tenant_id` varchar(40) NOT NULL DEFAULT '' COMMENT '租户id', - PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='流程变量'; - -SET FOREIGN_KEY_CHECKS = 1; -ALTER TABLE proc_instance ADD app_status varchar(20) NOT NULL DEFAULT 'ACTIVE' COMMENT 'app状态' after STATUS; - - -ALTER TABLE process.proc_history_task ADD comments TEXT NULL; -ALTER TABLE process.proc_task ADD comments TEXT NULL; -ALTER TABLE proc_node_instance ADD comments TEXT NULL; \ No newline at end of file diff --git a/deployment/deployment/search_index/Chart.yaml b/deployment/deployment/search_index/Chart.yaml deleted file mode 100644 index aa89f49..0000000 --- a/deployment/deployment/search_index/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Kubernetes -name: searchjob -version: 0.1.0 diff --git a/deployment/deployment/search_index/templates/_helpers.tpl b/deployment/deployment/search_index/templates/_helpers.tpl deleted file mode 100644 index ed71d56..0000000 --- a/deployment/deployment/search_index/templates/_helpers.tpl +++ /dev/null @@ -1,56 +0,0 @@ -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "audit.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 "audit.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "audit.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Common labels -*/}} -{{- define "audit.labels" -}} -app.kubernetes.io/name: {{ include "audit.name" . }} -helm.sh/chart: {{ include "audit.chart" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end -}} - -{{/* -Create the name of the service account to use -*/}} -{{- define "audit.serviceAccountName" -}} -{{- if .Values.serviceAccount.create -}} - {{ default (include "audit.fullname" .) .Values.serviceAccount.name }} -{{- else -}} - {{ default "default" .Values.serviceAccount.name }} -{{- end -}} -{{- end -}} diff --git a/deployment/deployment/search_index/templates/job.yaml b/deployment/deployment/search_index/templates/job.yaml deleted file mode 100644 index 8755a35..0000000 --- a/deployment/deployment/search_index/templates/job.yaml +++ /dev/null @@ -1,34 +0,0 @@ -kind: Job -apiVersion: batch/v1 -metadata: - name: search-job - namespace: {{ .Values.namespace }} - labels: - app: search-job -spec: - parallelism: 1 - completions: 1 - activeDeadlineSeconds: 3600 - backoffLimit: 1 - template: - metadata: - labels: - app: search-job - job-name: search-job - spec: - containers: - - name: container-o55dxy - image: '{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }}' - resources: {} - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - imagePullPolicy: Always - restartPolicy: Never - terminationGracePeriodSeconds: 30 - dnsPolicy: ClusterFirst - serviceAccountName: default - serviceAccount: default - securityContext: {} - imagePullSecrets: - - name: {{ .Values.imagePullSecrets }} - schedulerName: default-scheduler \ No newline at end of file diff --git a/deployment/deployment/search_index/values.yaml b/deployment/deployment/search_index/values.yaml deleted file mode 100644 index 3b8debb..0000000 --- a/deployment/deployment/search_index/values.yaml +++ /dev/null @@ -1,6 +0,0 @@ -image: - name: search_index - repo: docker.io/quanxiang - tag: v1.1.2 -namespace: "" -imagePullSecrets: "" diff --git a/deployment/go.mod b/deployment/go.mod deleted file mode 100644 index 1fc05fc..0000000 --- a/deployment/go.mod +++ /dev/null @@ -1,23 +0,0 @@ -module quanxiang - -go 1.16 - -require ( - github.com/containerd/containerd v1.6.2 // indirect - github.com/docker/distribution v2.8.1+incompatible // indirect - github.com/docker/docker v20.10.14+incompatible - github.com/fsnotify/fsnotify v1.5.1 // indirect - github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect - github.com/onsi/ginkgo v1.16.5 // indirect - github.com/onsi/gomega v1.18.1 // indirect - github.com/opencontainers/image-spec v1.0.2 // indirect - github.com/satori/go.uuid v1.2.0 - github.com/spf13/cobra v1.4.0 - golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd - google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368 // indirect - gopkg.in/yaml.v2 v2.4.0 - gotest.tools/v3 v3.1.0 // indirect - k8s.io/apimachinery v0.24.2 - k8s.io/client-go v0.24.2 - sigs.k8s.io/yaml v1.3.0 -) diff --git a/deployment/go.sum b/deployment/go.sum deleted file mode 100644 index 0aa1150..0000000 --- a/deployment/go.sum +++ /dev/null @@ -1,1481 +0,0 @@ -bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= -bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM= -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= -github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= -github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= -github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= -github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= -github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= -github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= -github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= -github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= -github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= -github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= -github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= -github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= -github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= -github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= -github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= -github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= -github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= -github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= -github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg= -github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= -github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= -github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= -github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= -github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= -github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= -github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= -github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= -github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= -github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= -github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= -github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= -github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= -github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= -github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= -github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= -github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= -github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= -github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= -github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= -github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= -github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= -github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= -github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= -github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E= -github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= -github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= -github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI= -github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= -github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= -github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= -github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= -github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= -github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= -github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8= -github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= -github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= -github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= -github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= -github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= -github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= -github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= -github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= -github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= -github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= -github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c= -github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s= -github.com/containerd/containerd v1.6.2 h1:pcaPUGbYW8kBw6OgIZwIVIeEhdWVrBzsoCfVJ5BjrLU= -github.com/containerd/containerd v1.6.2/go.mod h1:sidY30/InSE1j2vdD1ihtKoJz+lWdaXMdiAeIupaf+s= -github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= -github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= -github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= -github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= -github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= -github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= -github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= -github.com/containerd/continuity v0.2.2/go.mod h1:pWygW9u7LtS1o4N/Tn0FoCFDIXZ7rxcMX7HX1Dmibvk= -github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= -github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= -github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= -github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= -github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= -github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= -github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU= -github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk= -github.com/containerd/go-cni v1.1.0/go.mod h1:Rflh2EJ/++BA2/vY5ao3K6WJRR/bZKsX123aPk+kUtA= -github.com/containerd/go-cni v1.1.3/go.mod h1:Rflh2EJ/++BA2/vY5ao3K6WJRR/bZKsX123aPk+kUtA= -github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= -github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= -github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= -github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= -github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= -github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0= -github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA= -github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow= -github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms= -github.com/containerd/imgcrypt v1.1.3/go.mod h1:/TPA1GIDXMzbj01yd8pIbQiLdQxed5ue1wb8bP7PQu4= -github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= -github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= -github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= -github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM= -github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= -github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= -github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= -github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= -github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= -github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ= -github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= -github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= -github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= -github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= -github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw= -github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y= -github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= -github.com/containerd/zfs v0.0.0-20210324211415-d5c4544f0433/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= -github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= -github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= -github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= -github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= -github.com/containernetworking/cni v1.0.1/go.mod h1:AKuhXbN5EzmD4yTNtfSsX3tPcmtrBI6QcRV0NiNt15Y= -github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= -github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8= -github.com/containernetworking/plugins v1.0.1/go.mod h1:QHCfGpaTwYTbbH+nZXKVTxNBDZcxSOplJT5ico8/FLE= -github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= -github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4= -github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= -github.com/containers/ocicrypt v1.1.2/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= -github.com/containers/ocicrypt v1.1.2/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= -github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= -github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= -github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= -github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= -github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= -github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= -github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= -github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= -github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= -github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= -github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v20.10.14+incompatible h1:+T9/PRYWNDo5SZl5qS1r9Mo/0Q8AwxKKPtu9S1yxM0w= -github.com/docker/docker v20.10.14+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= -github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= -github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= -github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= -github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= -github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= -github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= -github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= -github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= -github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= -github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= -github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= -github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= -github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= -github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= -github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= -github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= -github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= -github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= -github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ= -github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= -github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw= -github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= -github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= -github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= -github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= -github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= -github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= -github.com/moby/sys/signal v0.6.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= -github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= -github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs= -github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= -github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= -github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= -github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= -github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.0.2-0.20211117181255-693428a734f5/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= -github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= -github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= -github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= -github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= -github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= -github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= -github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= -github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= -github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= -github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= -github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= -github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= -github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= -github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= -github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= -github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= -github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= -github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= -github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= -github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= -github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= -github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= -github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= -github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= -go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= -go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= -go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= -go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= -go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0/go.mod h1:vEhqr0m4eTc+DWxfsXoXue2GBgV2uUwVznkGIHW/e5w= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= -go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= -go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs= -go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDDKDkvI9dP/FIhpmna5lkqPUQdEjFAM8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0/go.mod h1:keUU7UfnwWTWpJ+FWnyqmogPa82nuU5VUANFq49hlMY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0/go.mod h1:QNX1aly8ehqqX1LEa6YniTU7VY9I6R3X/oPxhGdTceE= -go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= -go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= -go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs= -go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= -go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= -go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= -go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368 h1:Et6SkiuvnBn+SgrSYXs/BrUpGB4mbdwt4R3vaPIlicA= -google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM= -google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= -gotest.tools/v3 v3.1.0 h1:rVV8Tcg/8jHUkPUorwjaMTtemIMVXfIPKiOqnhEhakk= -gotest.tools/v3 v3.1.0/go.mod h1:fHy7eyTmJFO5bQbUsEGQ1v4m2J3Jz9eWL54TP2/ZuYQ= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= -k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= -k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= -k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs= -k8s.io/api v0.24.2 h1:g518dPU/L7VRLxWfcadQn2OnsiGWVOadTLpdnqgY2OI= -k8s.io/api v0.24.2/go.mod h1:AHqbSkTm6YrQ0ObxjO3Pmp/ubFF/KuM7jU+3khoBsOg= -k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= -k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= -k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U= -k8s.io/apimachinery v0.24.2 h1:5QlH9SL2C8KMcrNJPor+LbXVTaZRReml7svPEh4OKDM= -k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= -k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= -k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= -k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= -k8s.io/apiserver v0.22.5/go.mod h1:s2WbtgZAkTKt679sYtSudEQrTGWUSQAPe6MupLnlmaQ= -k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= -k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= -k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= -k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y= -k8s.io/client-go v0.24.2 h1:CoXFSf8if+bLEbinDqN9ePIDGzcLtqhfd6jpfnwGOFA= -k8s.io/client-go v0.24.2/go.mod h1:zg4Xaoo+umDsfCWr4fCnmLEtQXyCNXCvJuSsglNcV30= -k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0= -k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= -k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= -k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= -k8s.io/component-base v0.22.5/go.mod h1:VK3I+TjuF9eaa+Ln67dKxhGar5ynVbwnGrUiNF4MqCI= -k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= -k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= -k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= -k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= -k8s.io/cri-api v0.23.1/go.mod h1:REJE3PSU0h/LOV1APBrupxrEJqnoxZC8KWzkBUHwrK4= -k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= -k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= -k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= -k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 h1:Gii5eqf+GmIEwGNKQYQClCayuJCe2/4fZUvF7VG99sU= -k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= -k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= -k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc= -k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= -sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y= -sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= -sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= -sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= -sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/deployment/main.go b/deployment/main.go deleted file mode 100644 index 9d7b58e..0000000 --- a/deployment/main.go +++ /dev/null @@ -1,42 +0,0 @@ -/* -Copyright 2020 QuanxiangCloud Authors -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. -*/ - -package main - -import ( - "quanxiang/cmd" -) - - -func main() { - cmd.Execute() - //router, err := restful.NewRouter() - //if err != nil { - // panic(err) - //} - //go router.Run() - // - //c := make(chan os.Signal, 1) - //signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) - //for { - // s := <-c - // switch s { - // case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT: - // router.Close() - // return - // case syscall.SIGHUP: - // default: - // return - // } - //} -} diff --git a/deployment/pkg/configMysql.go b/deployment/pkg/configMysql.go deleted file mode 100644 index a5cf73f..0000000 --- a/deployment/pkg/configMysql.go +++ /dev/null @@ -1,86 +0,0 @@ -/* -Copyright 2020 QuanxiangCloud Authors -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. -*/ - -package pkg - -import ( - "context" - "errors" - "fmt" - "path/filepath" - "strings" - "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" - "k8s.io/client-go/util/homedir" -) - -func deployMysql(kubeconfig, namespace, sqlName, depPath string, configs *Configs) error { - if kubeconfig == "" || kubeconfig == "~/.kube/config" { - if home := homedir.HomeDir(); home != "" { - kubeconfig = filepath.Join(home, ".kube", "config") - } else { - fmt.Println("-------请输入 -k 参数获取kubeconfig信息") - return errors.New("NO_KUBECONFIG") - } - } - config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) - if err != nil { - panic(err.Error()) - } - - // create the clientset - clientset, err := kubernetes.NewForConfig(config) - if err != nil { - panic(err.Error()) - } - pods, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{}) - if err != nil { - fmt.Println(err) - } - var needMysql = true - for _, pod := range pods.Items { - if strings.Contains(pod.Name, "mysql") { - needMysql = false - } - } - - if needMysql { - err := mysqlInstall(namespace, depPath, "qxp1234", kubeconfig, configs.Persis) - if err != nil { - return err - } - fmt.Println("请稍等.........") - time.Sleep(30 * time.Second) - } - mysqlHost, err := AddrParase(configs.Config.Mysql.Host, namespace) - if err != nil { - return err - } - mysqlAddress := strings.Split(mysqlHost, ":")[0] - mysqlPort := strings.Split(configs.Config.Mysql.Host, ":")[1] - mysqlUserName := configs.Config.Mysql.User - mysqlUserPass := configs.Config.Mysql.Password - for _, pod := range pods.Items { - if strings.Contains(pod.Name, "mysql") { - command := "kubectl exec -it -n " + namespace + " --kubeconfig " + kubeconfig + " " + pod.Name + " -- mysql -h" + mysqlAddress + " -u" + mysqlUserName + " -p" + mysqlUserPass + " -P" + mysqlPort + " --default-character-set=utf8 < " + sqlName - err := execBash(command) - if err != nil { - return err - } - } - } - return nil -} diff --git a/deployment/pkg/configs.go b/deployment/pkg/configs.go deleted file mode 100644 index 9324efb..0000000 --- a/deployment/pkg/configs.go +++ /dev/null @@ -1,223 +0,0 @@ -/* -Copyright 2020 QuanxiangCloud Authors -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. -*/ - -package pkg - -import ( - "io/ioutil" - - "gopkg.in/yaml.v2" -) - -// Mysql -type Mysql struct { - Db string `yaml:"db"` - Host string `yaml:"host"` - User string `yaml:"user"` - Password string `yaml:"password"` - Log bool `yaml:"log"` -} - -// MiddlewareElastic -type MiddlewareElastic struct { - Enabled bool `yaml:"enabled"` -} - -// Elastic -type Elastic struct { - Log bool `yaml:"log"` - Host []string `yaml:"host"` -} - -// Credential -type Credential struct { - AuthMechanism string `yaml:"authMechanism"` - AuthSource string `yaml:"authSource"` - Username string `yaml:"username"` - Password string `yaml:"password"` - PasswordSet bool `yaml:"passwordSet"` -} - -// Storage -type Storage struct { - Option string `yaml:"option"` - UrlExpire int `yaml:"urlExpire"` - PartExpire int `yaml:"partExpire"` - Launch bool `yaml:"launch"` - Storages []Storages `yaml:"storages"` -} - -// Kafka -type Kafka struct { - Broker []string `yaml:"broker"` -} - -// MiddlewareKafka -type MiddlewareKafka struct { - Enabled bool `yaml:"enabled"` -} - -// MiddlewareRedis -type MiddlewareRedis struct { - Enabled bool `yaml:"enabled"` - Password string `yaml:"password"` -} - -// Middleware -type Configs struct { - Image Image `yaml:"image"` - ImagePullSecrets interface{} `yaml:"imagePullSecrets"` - Domain string `yaml:"domain"` - Args Args `yaml:"args"` - Persis Persis `yaml:"persis"` - Faas Faas `yaml:"faas"` - Config Config `yaml:"config"` - Elastic MiddlewareElastic `yaml:"elastic"` - Mongo MiddlewareMongo `yaml:"mongo"` - Kafka MiddlewareKafka `yaml:"kafka"` - Minio Minio `yaml:"minio"` - Mysql MiddlewareMysql `yaml:"mysql"` - Etcd Etcd `yaml:"etcd"` - Redis MiddlewareRedis `yaml:"redis"` - Dapr Dapr `yaml:"dapr"` -} - -// Faas -type Git struct { - Host string `yaml:"host"` - KnownHostsScan string `yaml:"known_hosts_scan"` - SSHPrivatekey string `yaml:"sshPrivatekey"` - GitSSHAddress string `yaml:"gitSSHAddress"` - GitSSHPort int `yaml:"gitSSHPort"` - Token string `yaml:"token"` -} - -// Faas -type Faas struct { - Docker Docker `yaml:"docker"` - Git Git `yaml:"git"` -} - -// Docker -type Docker struct { - Host string `yaml:"host"` - NameSpace string `yaml:"nameSpace"` - User string `yaml:"user"` - Pass string `yaml:"pass"` -} - -type Persis struct { - Enabled bool `yaml:"enabled"` - StorageClassName string `yaml:"storageClassName"` -} -type Args struct { - Enabled bool `yaml:"enabled"` - Endpoint string `yaml:"endpoint"` - Ip string `yaml:"ip"` -} - -// Config -type Config struct { - Redis Redis `yaml:"redis"` - Elastic Elastic `yaml:"elastic"` - Kafka Kafka `yaml:"kafka"` - Mongo Mongo `yaml:"mongo"` - Email Email `yaml:"email"` - Storage Storage `yaml:"storage"` - Etcd Etcd `yaml:"etcd"` - Mysql Mysql `yaml:"mysql"` -} - -type Dapr struct { - Enabled bool `yaml:"enabled"` -} - -// Redis -type Redis struct { - Addrs []string `yaml:"addrs"` - Username string `yaml:"username"` - Password string `yaml:"password"` -} - -// Minio -type Minio struct { - Enabled bool `yaml:"enabled"` - AccessKey string `yaml:"accessKey"` - SecretKey string `yaml:"secretKey"` -} -type Etcd struct { - Enabled bool `yaml:"enabled"` - Addrs []string `yaml:"addrs"` - Username interface{} `yaml:"username"` - Password string `yaml:"password"` -} - -// Email -type Email struct { - Enabled bool `yaml:"enabled"` - Host string `yaml:"host"` - Port int `yaml:"port"` - UserName string `yaml:"username"` - Password string `yaml:"password"` - Alias string `yaml:"alias"` - Sender string `yaml:"sender"` -} - -// Storages -type Storages struct { - Name string `yaml:"name"` - Protocol string `yaml:"protocol"` - Domain string `yaml:"domain"` - AccessKey string `yaml:"accessKey"` - SecretKey string `yaml:"secretKey"` - Location string `yaml:"location"` - BucketName string `yaml:"bucketName"` -} - -// MiddlewareMysql -type MiddlewareMysql struct { - Enabled bool `yaml:"enabled"` - RootPassword string `yaml:"rootPassword"` -} - -// Image -type Image struct { - Repo string `yaml:"repo"` - Tag string `yaml:"tag"` -} - -// Mongo -type Mongo struct { - Hosts []string `yaml:"hosts"` - Direct bool `yaml:"direct"` - Credential Credential `yaml:"credential"` -} - -// MiddlewareMongo -type MiddlewareMongo struct { - Password string `yaml:"rootPassword"` - Enabled bool `yaml:"enabled"` -} - -func ParaseConfig(filepath string) (*Configs, error) { - c := new(Configs) - buf, err := ioutil.ReadFile(filepath) - if err != nil { - return nil, err - } - err = yaml.Unmarshal(buf, c) - if err != nil { - return nil, err - } - return c, nil -} diff --git a/deployment/pkg/execcmd.go b/deployment/pkg/execcmd.go deleted file mode 100644 index 2c9ee2b..0000000 --- a/deployment/pkg/execcmd.go +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright 2020 QuanxiangCloud Authors -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. -*/ - -package pkg - -import ( - "bufio" - "fmt" - "io" - "os/exec" - "strings" -) - -func execBash(command string) error { - cmd := exec.Command("/bin/bash", "-c", command) - // 非阻塞输出 - stdout, err := cmd.StdoutPipe() - if err != nil { - return fmt.Errorf("stdout报错:%s", err.Error()) - } - - stderr, err := cmd.StderrPipe() - if err != nil { - return fmt.Errorf("stderr报错:%s", err.Error()) - } - - cmd.Start() - reader := bufio.NewReader(stdout) - for { - _, err2 := reader.ReadString('\n') - if err2 != nil || io.EOF == err2 { - break - } - //fmt.Printf("%s", line) - } - readerstderr := bufio.NewReader(stderr) - for { - stderrs, err2 := readerstderr.ReadString('\n') - if err2 != nil || io.EOF == err2 { - break - } - if strings.Contains(strings.ToLower(stderrs),"err") { - fmt.Printf("%s", stderrs) - } - } - cmd.Wait() - return nil -} diff --git a/deployment/pkg/importImages.go b/deployment/pkg/importImages.go deleted file mode 100644 index f13d635..0000000 --- a/deployment/pkg/importImages.go +++ /dev/null @@ -1,89 +0,0 @@ -package pkg - -import ( - "bytes" - "encoding/base64" - "encoding/json" - "fmt" - "io/ioutil" - "log" - "os" - "strings" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/client" - "golang.org/x/net/context" -) - -func importImages(registry, depFile, repoUser, repoPass string) { - fmt.Println() - fmt.Println("----------------------------------------->开始导入镜像") - cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) - if err != nil { - panic(err) - } - releases, _ := ioutil.ReadDir(depFile + "/images") - for _, release := range releases { - fileName := depFile + "/images/" + release.Name() - file, err := os.OpenFile(fileName, os.O_RDONLY, 0666) - if err != nil { - log.Fatalf("Error loading image %s, %s", fileName, err.Error()) - } else { - defer file.Close() - imageLoadResponse, err := cli.ImageLoad(context.Background(), file, true) - if err != nil { - log.Fatal(err) - } - body, err := ioutil.ReadAll(imageLoadResponse.Body) - if err != nil { - fmt.Println(err) - } - imageTag := strings.Replace(strings.Split(string(body), ":")[3], "\\n\"}", "", -1) - imageSource := strings.TrimSpace(strings.Split(string(body), ":")[2] + ":" + imageTag) - imageDes := registry + "/" + strings.TrimSpace(strings.Split(strings.Split(string(body), ":")[2], "/")[len(strings.Split(strings.Split(string(body), ":")[2], "/"))-1]) + - ":" + imageTag - imageDes = strings.TrimSpace(imageDes) - err = cli.ImageTag(context.Background(), imageSource, imageDes) - if err != nil { - log.Fatal(err) - } - - user := repoUser - password := repoPass - authConfig := types.AuthConfig{Username: user, Password: password} - encodedJSON, err := json.Marshal(authConfig) - if err != nil { - panic(err) - } - authStr := base64.URLEncoding.EncodeToString(encodedJSON) - pushReader, err := cli.ImagePush(context.Background(), imageDes, types.ImagePushOptions{ - All: false, - RegistryAuth: authStr, - PrivilegeFunc: nil, - }) - if err != nil { - panic(err.Error()) - } - defer pushReader.Close() - buf1 := new(bytes.Buffer) - buf1.ReadFrom(pushReader) - s1 := buf1.String() - if strings.Contains(s1, "err") { - fmt.Println(s1) - } else { - fmt.Printf("----------------------------------------->%s 镜像导入完成 \n", imageDes) - } - - //删除原镜像 *****净化环境 - _, err = cli.ImageRemove(context.Background(), imageSource, types.ImageRemoveOptions{}) - if err != nil { - panic(err.Error()) - } - //删除生成镜像 - _, err = cli.ImageRemove(context.Background(), imageDes, types.ImageRemoveOptions{}) - if err != nil { - panic(err.Error()) - } - } - } -} diff --git a/deployment/pkg/installFaas.go b/deployment/pkg/installFaas.go deleted file mode 100644 index d7981ce..0000000 --- a/deployment/pkg/installFaas.go +++ /dev/null @@ -1,135 +0,0 @@ -package pkg - -import ( - "encoding/base64" - "errors" - "fmt" - "os" - "strings" - - "gopkg.in/yaml.v2" -) - -type SecretSSH struct { - Kind string `yaml:"kind"` // Secret - ApiVersion string `yaml:"apiVersion"` // v1 - Data SSHData `yaml:"data"` - Meta MetaData `yaml:"metadata"` - Type string `yaml:"type"` //kubernetes.io/ssh-auth -} - -type SSHAnnota struct { - Token string `yaml:"tekton.dev/git-0"` // 'http://192.168.208.51:8080' -} -type MetaData struct { - Name string `yaml:"name" json:"name,omitempty"` // rsa - NameSpace string `yaml:"namespace" json:"name_space,omitempty"` //builder - Annotations SSHAnnota `yaml:"annotations" json:"annotations,omitempty"` -} -type SSHData struct { - KnownHosts string `yaml:"known_hosts"` //使用 ssh-keyscan -p 22端口 gitlab域名或者ip |base64 -w 0 生成 - SSHPrivatekey string `yaml:"ssh-privatekey"` //ssh-keygen -t rsa -f git_rsa -C "admin@quanxiang.dev" 生成ssh key, 将私钥使用base64编码, cat git_rsa|base64 -w 0 -} - -func InitFaas(kubeconfig, namespace, depPath string, configs *Configs) error { - sqlFile := "./initfaas.sql" - knowHosts := fmt.Sprintf("ssh://git@%s:%d/", configs.Faas.Git.GitSSHAddress, configs.Faas.Git.GitSSHPort) - knowHostsScan := fmt.Sprintf("ssh://%s:%d/", configs.Faas.Git.GitSSHAddress, configs.Faas.Git.GitSSHPort) - sshKey := DecodeBase64String(configs.Faas.Git.SSHPrivatekey) - if sshKey == "" { - return errors.New("decoder ssh failed") - } - gitSql := fmt.Sprintf("insert into gits (id, host, token, name, known_hosts, key_scan_known_hosts, ssh) values('%s', '%s','%s', '%s','%s', '%s', '%s');", - "mzHjx1QR", configs.Faas.Git.Host, configs.Faas.Git.Token, "rsa", knowHosts, knowHostsScan, string(sshKey)) - dockerSql := fmt.Sprintf("insert into dockers (id, host, user_name, name_space, secret, name) values('aZhvb2qR', '%s', '%s', '%s', '%s', '%s');", - configs.Faas.Docker.Host, configs.Faas.Docker.User, configs.Faas.Docker.NameSpace, configs.Faas.Docker.Pass, "faas-docker") - dbUse := "USE faas;\n" - _, err := os.Stat(sqlFile) - if err == nil { - _ = os.Remove(sqlFile) - } - f, err := os.OpenFile(sqlFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) - if err != nil { - return err - } - defer f.Close() - str := fmt.Sprintf("%s\n%s\n%s\n", dbUse, gitSql, dockerSql) - _, err = f.Write([]byte(str)) - if err != nil { - return err - } - err = deployMysql(kubeconfig, namespace, "./initfaas.sql", depPath, configs) - if err != nil { - return err - } - return err -} - -func applyGitSecret(host, known_hosts, ssh, kubeconfig, namespace string) error { - var sshSecret SecretSSH - yamlFile := "./secret.yaml" - - sshSecret.ApiVersion = "v1" - sshSecret.Kind = "Secret" - sshSecret.Type = "kubernetes.io/ssh-auth" - sshSecret.Data.KnownHosts = known_hosts - sshSecret.Meta.Annotations.Token = host - sshSecret.Meta.Name = "rsa" - sshSecret.Meta.NameSpace = namespace - sshSecret.Data.SSHPrivatekey = ssh - - sshBytes, err := yaml.Marshal(&sshSecret) - if err != nil { - fmt.Println(err) - return err - } - _, err = os.Stat(yamlFile) - if err == nil { - _ = os.Remove(yamlFile) - } - f, err := os.OpenFile(yamlFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) - if err != nil { - return err - } - defer f.Close() - _, err = f.Write(sshBytes) - if err != nil { - fmt.Println(err) - return err - } - command := fmt.Sprintf("kubectl apply -f %s --kubeconfig %s", yamlFile, kubeconfig) - err = execBash(command) - if err != nil { - return err - } - return err -} - -func applyHarbor(username, password, server, kubeconfig string) error { - command := "kubectl create secret docker-registry faas-docker --docker-username=" + username + " --docker-password=" + password + " --docker-server=" + server + " -n builder" + " --kubeconfig " + kubeconfig - err := execBash(command) - if err != nil { - return err - } - command = "kubectl create secret docker-registry faas-docker --docker-username=" + username + " --docker-password=" + password + " --docker-server=" + server + " -n serving" + " --kubeconfig " + kubeconfig - err = execBash(command) - if err != nil { - return err - } - return nil -} - -func DecodeBase64String(enc string) string { - reader := strings.NewReader(enc) - decoder := base64.NewDecoder(base64.RawStdEncoding, reader) - buf := make([]byte, 1024) - dst := "" - for { - n, err := decoder.Read(buf) - dst += string(buf[:n]) - if err != nil || n == 0 { - break - } - } - return dst -} diff --git a/deployment/pkg/middlerwareInstall.go b/deployment/pkg/middlerwareInstall.go deleted file mode 100644 index 059a5ee..0000000 --- a/deployment/pkg/middlerwareInstall.go +++ /dev/null @@ -1,478 +0,0 @@ -/* -Copyright 2020 QuanxiangCloud Authors -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. -*/ - -package pkg - -import ( - "errors" - "fmt" - "path/filepath" - "strings" - - "k8s.io/client-go/util/homedir" -) - -func middlewareInstall(namespace, depPath, kubeconfig, registry string, configs *Configs, isOffline bool) (bool, error) { - needMiddleware := false - if kubeconfig == "" { - if home := homedir.HomeDir(); home != "" { - kubeconfig = filepath.Join(home, ".kube", "config") - } else { - fmt.Println("-------请输入 -k 参数获取kubeconfig信息") - return needMiddleware, errors.New("NO_KUBECONFIG") - } - } - if !isOffline { - if configs.Dapr.Enabled { - err := installDapr(depPath, kubeconfig) - if err != nil { - fmt.Println("安装dapr时出现错误,请检查") - return needMiddleware, err - } - } - - if configs.Mysql.Enabled { - needMiddleware = true - err := mysqlInstall(namespace, depPath, configs.Mysql.RootPassword, kubeconfig, configs.Persis) - if err != nil { - fmt.Println("安装mysql时出现错误,请检查") - return needMiddleware, err - } - } - if configs.Elastic.Enabled { - needMiddleware = true - err := elasticsearchInstall(namespace, depPath, kubeconfig, configs.Persis) - if err != nil { - fmt.Println("安装elasticsearch时出现错误,请检查") - return needMiddleware, err - } - } - /* - if configs.Etcd.Enabled { - needMiddleware = true - err := etcdInstall(namespace, depPath, kubeconfig, configs.Persis) - if err != nil { - fmt.Println("安装minio时出现错误,请检查") - return needMiddleware, err - } - } - */ - if configs.Kafka.Enabled { - needMiddleware = true - err := kafKaInstall(namespace, depPath, kubeconfig, configs.Persis) - if err != nil { - fmt.Println("安装kafka时出现错误,请检查") - return needMiddleware, err - } - } - if configs.Redis.Enabled { - needMiddleware = true - err := redisInstall(namespace, depPath, configs.Redis.Password, kubeconfig) - if err != nil { - fmt.Println("安装redis时出现错误,请检查") - return needMiddleware, err - } - } - if configs.Mongo.Enabled { - needMiddleware = true - err := mongodbInstall(namespace, depPath, configs.Mongo.Password, kubeconfig, configs.Persis) - if err != nil { - fmt.Println("安装mongodb时出现错误,请检查") - return needMiddleware, err - } - - } - if configs.Minio.Enabled { - needMiddleware = true - err := minio(namespace, depPath, configs.Minio.AccessKey, configs.Minio.SecretKey, configs.Args.Endpoint, kubeconfig, configs.Persis) - if err != nil { - fmt.Println("安装minio时出现错误,请检查") - return needMiddleware, err - } - } - } else { - err := installDaprOffLine(depPath, kubeconfig, registry) - if err != nil { - fmt.Println("安装dapr时出现错误,请检查") - return needMiddleware, err - } - if configs.Mysql.Enabled { - needMiddleware = true - err := mysqlInstallOffLine(namespace, depPath, configs.Mysql.RootPassword, kubeconfig, registry, configs.Persis) - if err != nil { - fmt.Println("安装mysql时出现错误,请检查") - return needMiddleware, err - } - } - if configs.Elastic.Enabled { - needMiddleware = true - err := elasticsearchInstallOffLine(namespace, depPath, kubeconfig, registry, configs.Persis) - if err != nil { - fmt.Println("安装elasticsearch时出现错误,请检查") - return needMiddleware, err - } - } - /* - if configs.Etcd.Enabled { - needMiddleware = true - err := etcdInstallOffLine(namespace, depPath, kubeconfig, registry, configs.Persis) - if err != nil { - fmt.Println("安装minio时出现错误,请检查") - return needMiddleware, err - } - } - */ - if configs.Kafka.Enabled { - needMiddleware = true - err := kafKaInstallOffLine(namespace, depPath, kubeconfig, registry, configs.Persis) - if err != nil { - fmt.Println("安装kafka时出现错误,请检查") - return needMiddleware, err - } - } - if configs.Redis.Enabled { - needMiddleware = true - err := redisInstallOffLine(namespace, depPath, configs.Redis.Password, kubeconfig, registry) - if err != nil { - fmt.Println("安装redis时出现错误,请检查") - return needMiddleware, err - } - } - if configs.Mongo.Enabled { - needMiddleware = true - err := mongodbInstallOffLine(namespace, depPath, configs.Mongo.Password, kubeconfig, registry, configs.Persis) - if err != nil { - fmt.Println("安装mongodb时出现错误,请检查") - return needMiddleware, err - } - - } - if configs.Minio.Enabled { - needMiddleware = true - err := minioOffLine(namespace, depPath, configs.Minio.AccessKey, configs.Minio.SecretKey, configs.Args.Endpoint, kubeconfig, registry, configs.Persis) - if err != nil { - fmt.Println("安装minio时出现错误,请检查") - return needMiddleware, err - } - } - } - - return needMiddleware, nil -} -func mysqlInstall(namespace, depPath, password, kubeconfig string, persis Persis) error { - fmt.Println("--------->开始部署MySQL") - var command string - if persis.Enabled { - command = "helm install mysql -n " + namespace + " " + depPath + "/middleware_deployment/mysql --set mysqlRootPassword=" + password + " --kubeconfig " + kubeconfig + " --timeout 1800s --create-namespace --set persistence.enabled=true --set persistence.storageClass=" + persis.StorageClassName - } else { - command = "helm install mysql -n " + namespace + " " + depPath + "/middleware_deployment/mysql --set mysqlRootPassword=" + password + " --kubeconfig " + kubeconfig + " --timeout 1800s --create-namespace" - } - - err := execBash(command) - if err != nil { - return err - } - return nil - -} -func mysqlInstallOffLine(namespace, depPath, password, kubeconfig, registry string, persis Persis) error { - fmt.Println("--------->开始部署MySQL") - var command string - if persis.Enabled { - command = "helm install mysql -n " + namespace + " " + depPath + "/middleware_deployment/mysql --set mysqlRootPassword=" + - password + " --kubeconfig " + kubeconfig + " --timeout 1800s --create-namespace --set image=" + registry + "/mysql --set busybox.image=" + registry + - "/busybox --set persistence.enabled=true --set persistence.storageClass=" + persis.StorageClassName - } else { - command = "helm install mysql -n " + namespace + " " + depPath + "/middleware_deployment/mysql --set mysqlRootPassword=" + - password + " --kubeconfig " + kubeconfig + " --timeout 1800s --create-namespace --set image=" + registry + "/mysql --set busybox.image=" + registry + - "/busybox" - } - - err := execBash(command) - if err != nil { - return err - } - return nil - -} -func zookeeperInstall(namespace, depPath, kubeconfig string, persis Persis) error { - fmt.Println("--------->开始部署Zookeeper") - var command string - if persis.Enabled { - command = "helm install zookeeper -n " + namespace + " " + depPath + "/middleware_deployment/zookeeper" + " --kubeconfig " + kubeconfig + - " --timeout 1800s --create-namespace --set persistence.enabled=true --set persistence.storageClass=" + persis.StorageClassName - } else { - command = "helm install zookeeper -n " + namespace + " " + depPath + "/middleware_deployment/zookeeper" + " --kubeconfig " + kubeconfig + - " --timeout 1800s --create-namespace" - } - err := execBash(command) - if err != nil { - return err - } - fmt.Println("--------->zookeeper安装完成") - return nil - -} -func zookeeperInstallOffLine(namespace, depPath, kubeconfig, registry string, persis Persis) error { - fmt.Println("--------->开始部署Zookeeper") - var command string - if persis.Enabled { - command = "helm install zookeeper -n " + namespace + " " + depPath + "/middleware_deployment/zookeeper" + - " --kubeconfig " + kubeconfig + " --timeout 1800s --create-namespace --set image.repository=" + registry + "/zookeeper --set persistence.enabled=true --set persistence.storageClass=" + persis.StorageClassName - } else { - command = "helm install zookeeper -n " + namespace + " " + depPath + "/middleware_deployment/zookeeper" + - " --kubeconfig " + kubeconfig + " --timeout 1800s --create-namespace --set image.repository=" + registry + "/zookeeper" - } - err := execBash(command) - if err != nil { - return err - } - fmt.Println("--------->zookeeper安装完成") - return nil - -} - -func kafKaInstall(namespace, depPath, kubeconfig string, persis Persis) error { - fmt.Println("--------->开始部署Kafka") - err := zookeeperInstall(namespace, depPath, kubeconfig, persis) - if err != nil { - return err - } - var command string - if persis.Enabled { - command = "helm install kafka -n " + namespace + " " + depPath + "/middleware_deployment/kafka" + " --kubeconfig " + kubeconfig + - " --timeout 1800s --create-namespace --set persistence.enabled=true --set persistence.storageClass=" + persis.StorageClassName - } else { - command = "helm install kafka -n " + namespace + " " + depPath + "/middleware_deployment/kafka" + " --kubeconfig " + kubeconfig + " --timeout 1800s --create-namespace" - } - - err = execBash(command) - if err != nil { - return err - } - return nil -} -func kafKaInstallOffLine(namespace, depPath, kubeconfig, registry string, persis Persis) error { - fmt.Println("--------->开始部署Kafka") - err := zookeeperInstallOffLine(namespace, depPath, kubeconfig, registry, persis) - if err != nil { - return err - } - var command string - if persis.Enabled { - command = "helm install kafka -n " + namespace + " " + depPath + "/middleware_deployment/kafka" + " --kubeconfig " + - kubeconfig + " --timeout 1800s --create-namespace --set image=" + registry + "/cp-kafka --set persistence.enabled=true --set persistence.storageClass=" + persis.StorageClassName - } else { - command = "helm install kafka -n " + namespace + " " + depPath + "/middleware_deployment/kafka" + " --kubeconfig " + - kubeconfig + " --timeout 1800s --create-namespace --set image=" + registry + "/cp-kafka" - } - err = execBash(command) - if err != nil { - return err - } - return nil -} - -func redisInstall(namespace, depPath, password, kubeconfig string) error { - fmt.Println("--------->开始部署Redis") - command := fmt.Sprintf("helm install redis-cluster -n %s %s/middleware_deployment/redis-cluster --set password=%s --kubeconfig %s --timeout 1800s --create-namespace", namespace, depPath, password, kubeconfig) - err := execBash(command) - if err != nil { - return err - } - return nil - -} -func redisInstallOffLine(namespace, depPath, password, kubeconfig, registry string) error { - fmt.Println("--------->开始部署Redis") - command := fmt.Sprintf("helm install redis -n %s %s /middleware_deployment/redis-cluster --set password=%s --kubeconfig %s --timeout 1800s --create-namespace --set operator.image_source=%s/redis --set operator.image_redis= %s/redis", - namespace, depPath, password, kubeconfig, registry, registry) - err := execBash(command) - if err != nil { - return err - } - return nil - -} - -func mongodbInstall(namespace, depPath, password, kubeconfig string, persis Persis) error { - fmt.Println("--------->开始部署mongodb") - var command string - if persis.Enabled { - command = "helm install mongodb -n " + namespace + " " + depPath + "/middleware_deployment/mongodb --set mongodbRootPassword=" + password + - " --kubeconfig " + kubeconfig + " --timeout 1800s --create-namespace --set persistence.enabled=true --set persistence.storageClass=" + persis.StorageClassName - } else { - command = "helm install mongodb -n " + namespace + " " + depPath + "/middleware_deployment/mongodb --set mongodbRootPassword=" + password + - " --kubeconfig " + kubeconfig + " --timeout 1800s --create-namespace" - } - err := execBash(command) - if err != nil { - return err - } - return nil - -} -func mongodbInstallOffLine(namespace, depPath, password, kubeconfig, registry string, persis Persis) error { - fmt.Println("--------->开始部署mongodb") - var command string - if persis.Enabled { - command = "helm install mongodb -n " + namespace + " " + depPath + "/middleware_deployment/mongodb --set mongodbRootPassword=" + - password + " --kubeconfig " + kubeconfig + " --timeout 1800s --create-namespace --set image.registry=" + registry + " --set image.repository=" + - "mongodb --set persistence.enabled=true --set persistence.storageClass=" + persis.StorageClassName - } else { - command = "helm install mongodb -n " + namespace + " " + depPath + "/middleware_deployment/mongodb --set mongodbRootPassword=" + - password + " --kubeconfig " + kubeconfig + " --timeout 1800s --create-namespace --set image.registry=" + registry + " --set image.repository=" + - "mongodb" - } - err := execBash(command) - if err != nil { - return err - } - return nil - -} - -func elasticsearchInstall(namespace, depPath, kubeconfig string, persis Persis) error { - fmt.Println("--------->开始部署elasticsearch") - var command string - if persis.Enabled { - command = "helm install elasticsearch -n " + namespace + " " + depPath + "/middleware_deployment/elasticsearch" + - " --kubeconfig " + kubeconfig + " --timeout 1800s --create-namespace --set persistence.enabled=true --set volumeClaimTemplate.storageClassName=" + persis.StorageClassName - } else { - command = "helm install elasticsearch -n " + namespace + " " + depPath + "/middleware_deployment/elasticsearch" + " --kubeconfig " + kubeconfig + " --timeout 1800s --create-namespace" - } - err := execBash(command) - if err != nil { - return err - } - return nil -} -func elasticsearchInstallOffLine(namespace, depPath, kubeconfig, registry string, persis Persis) error { - fmt.Println("--------->开始部署elasticsearch") - var command string - if persis.Enabled { - command = "helm install elasticsearch -n " + namespace + " " + depPath + "/middleware_deployment/elasticsearch" + - " --kubeconfig " + kubeconfig + " --timeout 1800s --create-namespace --set image.repository=" + registry + "/elasticsearch-oss --set initImage.repository=" + - registry + "/busybox --set persistence.enabled=true --set volumeClaimTemplate.storageClassName=" + persis.StorageClassName - } else { - command = "helm install elasticsearch -n " + namespace + " " + depPath + "/middleware_deployment/elasticsearch" + - " --kubeconfig " + kubeconfig + " --timeout 1800s --create-namespace --set image.repository=" + registry + "/elasticsearch-oss --set initImage.repository=" + - registry + "/busybox" - } - err := execBash(command) - if err != nil { - return err - } - return nil -} - -/* -func etcdInstall(namespace, depPath, kubeconfig string, persis Persis) error { - fmt.Println("--------->开始部署etcd") - var command string - path := depPath + "/middleware_deployment/etcd-operator/values-persis.yaml" - if persis.Enabled { - command = "helm install etcd-operator -n " + namespace + " " + depPath + "/middleware_deployment/etcd-operator --kubeconfig " + kubeconfig + - " --timeout 1800s --set etcdCluster.pod.persistentVolumeClaimSpec.storageClassName=" + persis.StorageClassName + " -f " + path - } else { - command = "helm install etcd-operator -n " + namespace + " " + depPath + "/middleware_deployment/etcd-operator --kubeconfig " + kubeconfig + " --timeout 1800s" - } - err := execBash(command) - if err != nil { - return err - } - return nil -} -func etcdInstallOffLine(namespace, depPath, kubeconfig, registry string, persis Persis) error { - fmt.Println("--------->开始部署etcd") - var command string - path := depPath + "/middleware_deployment/etcd-operator/values-persis.yaml" - if persis.Enabled { - command = "helm install etcd-operator -n " + namespace + " " + - depPath + "/middleware_deployment/etcd-operator --kubeconfig " + - kubeconfig + " --timeout 1800s --set etcdOperator.image.repository=" + registry + "/etcd-operator --set backupOperator.image.repository=" + registry + - "/etcd-operator --set restoreOperator.image.repository=" + registry + "/etcd-operator --set etcdCluster.image.repository=" + registry + "/etcd --set etcdCluster.pod.busyboxImage=" + - registry + "/busybox:1.28.0-glibc --set etcdCluster.pod.persistentVolumeClaimSpec.storageClassName=" + persis.StorageClassName + " -f " + path - } else { - command = "helm install etcd-operator -n " + namespace + " " + - depPath + "/middleware_deployment/etcd-operator --kubeconfig " + - kubeconfig + " --timeout 1800s --set etcdOperator.image.repository=" + registry + "/etcd-operator --set backupOperator.image.repository=" + registry + - "/etcd-operator --set restoreOperator.image.repository=" + registry + "/etcd-operator --set etcdCluster.image.repository=" + registry + "/etcd --set etcdCluster.pod.busyboxImage=" + registry + "/busybox:1.28.0-glibc" - } - err := execBash(command) - if err != nil { - return err - } - return nil -} -*/ -func minio(namespace, depPath, accessKey, secretKey, envdomain, kubeconfig string, persis Persis) error { - fmt.Println("--------->开始部署minio") - envdomain = strings.Split(envdomain, ":")[0] - var command string - if persis.Enabled { - command = "helm install minio -n " + namespace + " " + depPath + - "/middleware_deployment/minio --set accessKey=" + - accessKey + " --set secretKey=" + secretKey + " --set env=fs." + envdomain + - " --kubeconfig " + kubeconfig + " --timeout 1800s --create-namespace --set persistence.enabled=true --set persistence.storageClass=" + persis.StorageClassName - } else { - command = "helm install minio -n " + namespace + " " + depPath + - "/middleware_deployment/minio --set accessKey=" + - accessKey + " --set secretKey=" + secretKey + " --set env=fs." + envdomain + - " --kubeconfig " + kubeconfig + " --timeout 1800s --create-namespace" - } - err := execBash(command) - if err != nil { - return err - } - return nil -} -func minioOffLine(namespace, depPath, accessKey, secretKey, envdomain, kubeconfig, registry string, persis Persis) error { - fmt.Println("--------->开始部署minio") - envdomain = strings.Split(envdomain, ":")[0] - var command string - if persis.Enabled { - command = "helm install minio -n " + namespace + - " " + depPath + "/middleware_deployment/minio --set accessKey=" + accessKey + - " --set secretKey=" + secretKey + " --set env=fs." + envdomain + " --kubeconfig " + - kubeconfig + " --timeout 1800s --create-namespace --set image.repository=" + registry + "/minio --set persistence.enabled=true --set persistence.storageClass=" + persis.StorageClassName - } else { - command = "helm install minio -n " + namespace + - " " + depPath + "/middleware_deployment/minio --set accessKey=" + accessKey + - " --set secretKey=" + secretKey + " --set env=fs." + envdomain + " --kubeconfig " + - kubeconfig + " --timeout 1800s --create-namespace --set image.repository=" + registry + "/minio" - } - err := execBash(command) - if err != nil { - return err - } - return nil -} -func installDapr(depfile, kubeconfig string) error { - fmt.Println("--------->开始部署dapr") - command := "helm upgrade dapr " + depfile + "/middleware_deployment/dapr --install --version=1.5 --namespace dapr-system --create-namespace --wait --kubeconfig " + kubeconfig - err := execBash(command) - if err != nil { - return err - } - return nil -} -func installDaprOffLine(depfile, kubeconfig, registry string) error { - fmt.Println("--------->开始部署dapr") - command := "helm upgrade dapr " + depfile + "/middleware_deployment/dapr --install --version=1.5 --namespace dapr-system --create-namespace --wait --kubeconfig " + kubeconfig + " --set global.registry=" + registry - err := execBash(command) - if err != nil { - return err - } - return nil -} diff --git a/deployment/pkg/modifyValues.go b/deployment/pkg/modifyValues.go deleted file mode 100644 index 9efe974..0000000 --- a/deployment/pkg/modifyValues.go +++ /dev/null @@ -1,332 +0,0 @@ -/* -Copyright 2020 QuanxiangCloud Authors -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. -*/ - -package pkg - -import ( - "bytes" - "fmt" - "io/ioutil" - "strings" - "text/template" - - uuid "github.com/satori/go.uuid" - "gopkg.in/yaml.v2" -) - -//project -type values struct { - Image struct { - Name string `yaml:"name"` - Repo string `yaml:"repo"` - Tag string `yaml:"tag"` - } - Namespace string `yaml:"namespace"` - Domain string `yaml:"domain"` - Mongo_host string `yaml:"mongo_host"` - Args struct { - Enabled bool `yaml:"enabled"` - Endpoint string `yaml:"endpoint"` - Ip string `yaml:"ip"` - } - Kafka struct { - Value string `yaml:"value"` - } - Redis struct { - Host string `yaml:"host"` - Password string `yaml:"password"` - } - ImagePullSecrets string `yaml:"imagePullSecrets"` - Service struct { - Type string `yaml:"type"` - Port int `yaml:"port"` - RpcPort int `yaml:"rpcPort"` - } - NameOverride string `yaml:"nameOverride"` - FullnameOverride string `yaml:"fullnameOverride"` - Websocket_hostname string `yaml:"websocket_hostname"` - Home_hostname string `yaml:"home_hostname"` - Portal_hostname string `yaml:"portal_hostname"` - Vendor Vendor `yaml:"vendor"` - ServiceAccount struct { - Create bool `yaml:"create"` - Name string `yaml:"name"` - } `yaml:"serviceAccount"` - ClusterRole ClusterRole `json:"clusterRole"` - PodSecurityContext map[string]interface{} `yaml:"podSecurityContext"` - SecurityContext map[string]interface{} `yaml:"securityContext"` - Config struct { - JwtKey string `yaml:"jwtKey"` - Mysql Mysql - Redis Redis - Elastic Elastic - Kafka Kafka - Mongo Mongo - Etcd Etcd - Storage Storage - Email Email - } - Ingress struct { - Enabled bool `yaml:"enabled"` - Hosts []struct { - Host string `yaml:"host"` - //Paths []struct{ - // Path string `yaml: path` - // FullName string `yaml: fullName` - // SvcPort int `yaml svcPort` - //}`yaml: paths` - Paths []map[string]interface{} `yaml:"paths"` - } `yaml:"hosts"` - } - App struct { - Kubernetes struct { - Io struct { - Name string `yaml:"name"` - } `yaml:"io"` - } `yaml:"kubernetes"` - } -} - -type Vendor struct { - Protocol string `yaml:"protocol"` - Hostname string `yaml:"hostname"` - Port int `yaml:"port"` -} - -type Annotations struct { - RbacAuthorizationKubernetesIoAutoupdate string `json:"rbac.authorization.kubernetes.io/autoupdate"` -} -type ClusterRole struct { - Create bool `json:"create"` - Name string `json:"name"` - Annotations Annotations `json:"annotations"` -} - -//func ReadAllValuesFile(configFile string) (*values,error) { -// all := new(values) -// data,err := ioutil.ReadFile(configFile) -// if err != nil { -// fmt.Println("读取value文件失败") -// return nil,err -// } -// err = yaml.Unmarshal(data,all) -// if err != nil { -// return nil,err -// } -// return all,nil -//} -func ModifyValuesFile(filepath, namespace string, configs *Configs, ngGateWay bool) error { - //all,err := ReadAllValuesFile(configFile) - //if err != nil { - // return err - //} - value := new(values) - data, err := ioutil.ReadFile(filepath) - if err != nil { - fmt.Println("读取value文件失败") - return err - } - err = yaml.Unmarshal(data, value) - if err != nil { - fmt.Println("读取数据失败") - return err - } - if configs.Mysql.Enabled { - value.Config.Mysql.Host, err = AddrParase(configs.Config.Mysql.Host, namespace) - if err != nil { - return err - } - value.Config.Mysql.Password = configs.Config.Mysql.Password - value.Config.Mysql.User = configs.Config.Mysql.User - value.Config.Mysql.Log = configs.Config.Mysql.Log - } else { - value.Config.Mysql.Host = configs.Config.Mysql.Host - value.Config.Mysql.Password = configs.Config.Mysql.Password - value.Config.Mysql.User = configs.Config.Mysql.User - value.Config.Mysql.Log = configs.Config.Mysql.Log - } - //value.Config.Redis = configs.Config.Redis - if strings.Contains(filepath, "flow") { - value.Redis.Host = "" - for _, v := range value.Config.Redis.Addrs { - value.Redis.Host += v - value.Redis.Host += "," - } - value.Redis.Host = strings.TrimSuffix(value.Redis.Host, ",") - value.Redis.Password = configs.Config.Redis.Password - } - if configs.Redis.Enabled { - for i, v := range value.Config.Redis.Addrs { - value.Config.Redis.Addrs[i], err = AddrParase(v, namespace) - if err != nil { - return err - } - } - value.Config.Redis.Username = configs.Config.Redis.Username - value.Config.Redis.Password = configs.Config.Redis.Password - } else { - value.Config.Redis = configs.Config.Redis - } - if configs.Elastic.Enabled { - ev, _ := AddrParase(configs.Config.Elastic.Host[0], namespace) - elas_v := []string{ev} - value.Config.Elastic.Host = elas_v - value.Config.Elastic.Log = configs.Config.Elastic.Log - } else { - value.Config.Elastic = configs.Config.Elastic - } - if configs.Mongo.Enabled { - mongoHost, err := AddrParase(configs.Config.Mongo.Hosts[0], namespace) - if err != nil { - fmt.Println(err) - } - if len(value.Config.Mongo.Hosts) == 0 { - value.Config.Mongo.Hosts = append(value.Config.Mongo.Hosts, mongoHost) - } - value.Config.Mongo.Hosts[0] = mongoHost - - value.Config.Mongo.Credential = configs.Config.Mongo.Credential - value.Config.Mongo.Direct = configs.Config.Mongo.Direct - } else { - value.Config.Mongo = configs.Config.Mongo - } - /* - if configs.Etcd.Enabled { - value.Config.Etcd.Addrs[0], err = AddrParase(configs.Config.Etcd.Addrs[0], namespace) - if err != nil { - fmt.Println(err) - } - for i, _ := range value.Config.Etcd.Addrs { - if i == 0 { - continue - } else { - value.Config.Etcd.Addrs[i] = "" - } - } - value.Config.Etcd.Username = configs.Config.Etcd.Username - value.Config.Etcd.Password = configs.Config.Etcd.Password - } else { - value.Config.Etcd.Addrs = configs.Config.Etcd.Addrs - value.Config.Etcd.Username = configs.Config.Etcd.Username - value.Config.Etcd.Password = configs.Config.Etcd.Password - } - */ - if strings.Contains(filepath, "portal") { - value.Ingress.Hosts[0].Host = "portal." + configs.Domain - value.Websocket_hostname = "ws." + configs.Domain - value.Home_hostname = "home." + configs.Domain - value.Portal_hostname = "portal." + configs.Domain - value.Vendor.Hostname = "vendors." + configs.Domain - value.Vendor.Port = 80 - value.Vendor.Protocol = "http" - } - - if strings.Contains(filepath, "home") { - value.Ingress.Hosts[0].Host = "home." + configs.Domain - value.Websocket_hostname = "ws." + configs.Domain - value.Home_hostname = "home." + configs.Domain - value.Portal_hostname = "portal." + configs.Domain - value.Vendor.Hostname = "vendors." + configs.Domain - value.Vendor.Port = 80 - value.Vendor.Protocol = "http" - } - if strings.Contains(filepath, "vendors") { - value.Ingress.Hosts[0].Host = "vendors." + configs.Domain - } - if strings.Contains(filepath, "fileserver") { - value.Ingress.Hosts[0].Host = "*.fs." + configs.Domain - value.Domain = configs.Domain - } - if strings.Contains(filepath, "polygate") { - value.Ingress.Hosts[0].Host = "ws." + configs.Domain - value.Ingress.Hosts[1].Host = "api." + configs.Domain - } - if strings.Contains(filepath, "polyapi") { - value.Ingress.Hosts[0].Host = "polyapi." + configs.Domain - } - if strings.Contains(filepath, "form") { - value.Mongo_host = value.Config.Mongo.Hosts[0] - } - if configs.Kafka.Enabled { - value.Config.Kafka.Broker[0], err = AddrParase(configs.Config.Kafka.Broker[0], namespace) - if err != nil { - fmt.Println(err) - } - for i, _ := range value.Config.Kafka.Broker { - if i == 0 { - continue - } else { - value.Config.Kafka.Broker[i] = "" - } - } - value.Kafka.Value = value.Config.Kafka.Broker[0] - } else { - value.Config.Kafka = configs.Config.Kafka - value.Kafka.Value = "" - for _, k := range configs.Config.Kafka.Broker { - k_n, _ := AddrParase(k, namespace) - value.Kafka.Value += k_n - value.Kafka.Value += "," - } - value.Kafka.Value = strings.TrimSuffix(value.Kafka.Value, ",") - } - - value.Image.Repo = configs.Image.Repo - value.Image.Tag = configs.Image.Tag - value.Config.Storage = configs.Config.Storage - value.Config.Email = configs.Config.Email - value.ImagePullSecrets = configs.ImagePullSecrets.(string) - value.Args.Endpoint = configs.Args.Endpoint - value.Args.Enabled = configs.Args.Enabled - value.Args.Ip = configs.Args.Ip - value.Domain = configs.Domain - if strings.Contains(filepath, "warden") { - value.Config.JwtKey = uuid.NewV4().String() - } - - if ngGateWay { - value.Websocket_hostname = value.Websocket_hostname + ":32032" - value.Portal_hostname = value.Portal_hostname + ":32032" - value.Home_hostname = value.Home_hostname + ":32032" - for _, m := range value.Config.Storage.Storages { - if m.Name == "minio" { - m.Domain = m.Domain + ":32032" - } - } - } - data_file, err := yaml.Marshal(value) - if err != nil { - fmt.Println("修改后解析错误") - return err - } - err = ioutil.WriteFile(filepath, data_file, 0644) - if err != nil { - fmt.Println("写出到文件错误") - return err - } - - return nil -} - -func AddrParase(addr, namespace string) (string, error) { - tmpl, err := template.New("test").Parse(addr) - if err != nil { - return "", err - } - var buf bytes.Buffer - err = tmpl.Execute(&buf, namespace) - if err != nil { - return "", err - } - return buf.String(), nil -} diff --git a/deployment/pkg/startInstall.go b/deployment/pkg/startInstall.go deleted file mode 100644 index 7057516..0000000 --- a/deployment/pkg/startInstall.go +++ /dev/null @@ -1,158 +0,0 @@ -/* -Copyright 2020 QuanxiangCloud Authors -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. -*/ - -package pkg - -import ( - "fmt" - "io/ioutil" - "strings" -) - -func Start(kubeconfig, namespace, configFile, depFile, registry, regisUser, regisPass string, mysqlInit, ngGateway, isOffline bool) { - if namespace != "default" { - command := "kubectl create ns " + namespace + " --kubeconfig " + kubeconfig - err := execBash(command) - if err != nil { - fmt.Println("创建命名空间错误,请检查") - } - //command = "kubectl create secret docker-registry lowcode --docker-username=qxpkevin --docker-password=LzbXp9Er --docker-server=qxcr.io -n " + namespace - } - if isOffline { - importImages(registry, depFile, regisUser, regisPass) - } - - if ngGateway && !isOffline { - command := "helm install nginx-ingress " + depFile + "/nginx-ingress-controller" + " --kubeconfig " + kubeconfig + " -n " + namespace + " --timeout 1800s" - execBash(command) - fmt.Printf("--------->%s 部署完成,如果出现Error错误请参照检查 \n", strings.Split(command, " ")[2]) - fmt.Println() - } - - if ngGateway && isOffline { - command := "helm install nginx-ingress " + depFile + "/nginx-ingress-controller" + " --kubeconfig " + kubeconfig + " -n " + - namespace + " --timeout 1800s --create-namespace --set image.registry=" + registry + " --set image.repository=nginx-ingress-controller --set defaultBackend.image.registry=" + - registry + " --set defaultBackend.image.repository=nginx" - execBash(command) - fmt.Printf("--------->%s 部署完成,如果出现Error错误请参照检查 \n", strings.Split(command, " ")[2]) - fmt.Println() - } - fmt.Println("--------------------------------------->开始部署中间件") - fmt.Println() - configs, err := ParaseConfig(configFile) - if err != nil { - fmt.Println(err) - return - } - needMiddleware, err := middlewareInstall(namespace, depFile, kubeconfig, registry, configs, isOffline) - if err != nil { - fmt.Println() - fmt.Println(err) - fmt.Println("--------------------------------------->中间件部署失败") - return - } - fmt.Println() - fmt.Println("----------------------------------------->中间件部署完成") - fmt.Println("--------------------------------------->正在检查中间件是否运行,请等待。。。。。。") - if needMiddleware { - err = statusCheck(kubeconfig, namespace) - if err != nil { - fmt.Println(err) - return - } - fmt.Println() - } else { - fmt.Println("--------------------------------------->中间件安装成功") - } - if mysqlInit { - fmt.Println("----------------------------------------->开始初始化mysql") - releases, _ := ioutil.ReadDir(depFile + "/schemas") - for _, release := range releases { - sqlName := "./deployment/schemas/" + release.Name() - err := deployMysql(kubeconfig, namespace, sqlName, depFile, configs) - if err != nil { - fmt.Println("---------------------------------------> 数据库初始化失败") - return - } - fmt.Printf("--------->%s 部署完成,如果出现Error错误请参照检查 \n", release.Name()) - } - fmt.Println("---------------------------------------> 数据库初始化完成") - } - fmt.Println() - fmt.Println("----------------------------------------->开始部署服务") - releases, _ := ioutil.ReadDir(depFile + "/quanxiang_charts") - for _, release := range releases { - if release.IsDir() { - fmt.Println("--------->部署" + release.Name() + "服务 \n") - if !strings.Contains(release.Name(), "fluent") && !strings.Contains(release.Name(), "builder") { - err := ModifyValuesFile(depFile+"/quanxiang_charts/"+release.Name()+"/values.yaml", namespace, configs, ngGateway) - if err != nil { - fmt.Println("修改values.yaml失败") - fmt.Println(err) - } - } - var command string - switch release.Name() { - case "builder": - command = fmt.Sprintf("helm install %s %s/quanxiang_charts/%s --kubeconfig %s -n builder --set namespace=%s --set lowcode=%s --timeout 1800s --create-namespace", - release.Name(), depFile, release.Name(), kubeconfig, "builder", namespace) - case "serving": - command = fmt.Sprintf("helm install %s %s/quanxiang_charts/%s --kubeconfig %s -n serving --set namespace=%s --timeout 1800s --create-namespace", - release.Name(), depFile, release.Name(), kubeconfig, "serving") - case "fluent": - command = fmt.Sprintf("helm install %s %s/quanxiang_charts/%s --kubeconfig %s -n builder --set namespace=%s --timeout 1800s --create-namespace", - release.Name(), depFile, release.Name(), kubeconfig, "builder") - case "fluent-bit": - eshost, err := AddrParase(configs.Config.Elastic.Host[0], namespace) - if err != nil { - fmt.Println(err) - } - esHosts := strings.Split(eshost, ":") - command = fmt.Sprintf("helm install %s %s/quanxiang_charts/%s --kubeconfig %s -n builder --set namespace=%s --timeout 1800s --set backend.es.host=%s --set backend.es.port=%s --create-namespace", - release.Name(), depFile, release.Name(), kubeconfig, "builder", esHosts[1][2:], esHosts[2]) - default: - command = fmt.Sprintf("helm install %s %s/quanxiang_charts/%s --kubeconfig %s -n %s --set namespace=%s --timeout 1800s --create-namespace", - release.Name(), depFile, release.Name(), kubeconfig, namespace, namespace) - } - execBash(command) - fmt.Printf("--------->%s 部署完成,如果出现Error错误请参照检查 \n", strings.Split(command, " ")[2]) - fmt.Println() - } - } - fmt.Println("----------------------------------------->开始进行部署状态检查") - err = statusCheck(kubeconfig, namespace) - if err != nil { - fmt.Println(err) - return - } - err = applyGitSecret(configs.Faas.Git.Host, configs.Faas.Git.KnownHostsScan, configs.Faas.Git.SSHPrivatekey, kubeconfig, "builder") - if err != nil { - fmt.Println(err) - } - err = applyHarbor(configs.Faas.Docker.User, configs.Faas.Docker.Pass, configs.Faas.Docker.Host, kubeconfig) - if err != nil { - fmt.Println(err) - } - - err = InitFaas(kubeconfig, namespace, depFile, configs) - if err != nil { - fmt.Println(err) - } - /* - command := "helm install searchindex " + depFile + "/search_index" + " --kubeconfig " + kubeconfig + " -n " + namespace + " --timeout 1800s" - execBash(command) - command = "helm install auth " + depFile + "/portalauth" + " --kubeconfig " + kubeconfig + " -n " + namespace + " --timeout 1800s" - execBash(command) - */ - fmt.Println("----------------------------------------->部署完成") -} diff --git a/deployment/pkg/statusCheck.go b/deployment/pkg/statusCheck.go deleted file mode 100644 index fe9b8c0..0000000 --- a/deployment/pkg/statusCheck.go +++ /dev/null @@ -1,88 +0,0 @@ -/* -Copyright 2020 QuanxiangCloud Authors -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. -*/ - -package pkg - -import ( - "context" - "errors" - "fmt" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" - "k8s.io/client-go/util/homedir" - "path/filepath" - "time" -) - -func statusCheck(kubeconfig, namespace string) error { - if kubeconfig == "" || kubeconfig == "~/.kube/config"{ - if home := homedir.HomeDir(); home != "" { - kubeconfig = filepath.Join(home, ".kube", "config") - }else { - fmt.Println("-------请输入 -k 参数获取kubeconfig信息") - return errors.New("NO_KUBECONFIG") - } - } - config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) - if err != nil { - panic(err.Error()) - } - - // create the clientset - clientset, err := kubernetes.NewForConfig(config) - if err != nil { - panic(err.Error()) - } - for { - pods, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{}) - if err != nil { - panic(err.Error()) - } - - podCount := 0 - for _,pod := range pods.Items{ - containerFlag := 0 - for _,stat := range pod.Status.Conditions{ - if stat.Status == "True"{ - containerFlag++ - } - if containerFlag == len(pod.Status.Conditions){ - podCount++ - } - } - } - if podCount == len(pods.Items) { - fmt.Println("----------------------------------------->安装成功") - return nil - }else { - fmt.Println("----------------------------------------->仍有服务没有启动完成,详细信息如下") - - for _,pod := range pods.Items{ - for _,reason := range pod.Status.ContainerStatuses{ - if reason.State.Waiting != nil { - fmt.Printf("POD %s 还未就绪, 原因为:%s \n",pod.Name,reason.State.Waiting.Reason) - }else if reason.State.Terminated != nil { - fmt.Printf("POD %s 还未就绪,原因为:%s \n", pod.Name, reason.State.Terminated.Reason) - }else{ - continue - } - - } - - } - } - fmt.Printf("--------------------------命名空间%s下有 %d 个 pods--------------------------\n", namespace,len(pods.Items)) - time.Sleep(10 * time.Second) - } -} diff --git a/deployment/pkg/testCondition.go b/deployment/pkg/testCondition.go deleted file mode 100644 index b40a9fe..0000000 --- a/deployment/pkg/testCondition.go +++ /dev/null @@ -1,75 +0,0 @@ -/* -Copyright 2020 QuanxiangCloud Authors -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. -*/ - -package pkg - -import ( - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "net" - "strings" - "time" -) - -func tcpGather(ip string, port string) bool { - isConn := false - - address := net.JoinHostPort(ip, port) - // 5 秒超时 - conn, err := net.DialTimeout("tcp", address, 5*time.Second) - - if err != nil { - isConn = false - } else { - if conn != nil { - isConn = true - _ = conn.Close() - } else { - isConn = false - } - } - return isConn -} - -func InitCondiion(filePath string) (map[string]string, error) { - var NameMapPort = map[string]string{} - file, err := ioutil.ReadFile(filePath) - if err != nil { - fmt.Println("读取配置文件错误,请检查!!!") - return nil, err - } - err = json.Unmarshal(file, &NameMapPort) - if err != nil { - fmt.Println("配置文件格式有问题,请检查!!!") - return nil, err - } - return NameMapPort, err -} -func TestCondition(filePath string) error { - TestItems, err := InitCondiion(filePath) - if err != nil { - return err - } - for itemKey, testItem := range TestItems { - ipAndPort := strings.Split(testItem, ":") - isConn := tcpGather(ipAndPort[0], ipAndPort[1]) - if !isConn { - fmt.Printf("安装前检查失败:%s 没有就绪!!! \n", itemKey) - return errors.New("NUILL_INSTALL") - } - fmt.Printf("安装前检查成功:%s 已经就绪!!! \n", itemKey) - } - return nil -} diff --git a/deployment/pkg/uninstall.go b/deployment/pkg/uninstall.go deleted file mode 100644 index 92478f3..0000000 --- a/deployment/pkg/uninstall.go +++ /dev/null @@ -1,114 +0,0 @@ -/* -Copyright 2020 QuanxiangCloud Authors -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. -*/ - -package pkg - -import ( - "errors" - "fmt" - "io/ioutil" - "path/filepath" - "strings" - - "k8s.io/client-go/util/homedir" -) - -func UninstallServece(namespace, depPath, kubeconfig string, uninstallMiddlerware bool, skipDapr bool) error { - if kubeconfig == "" { - if home := homedir.HomeDir(); home != "" { - kubeconfig = filepath.Join(home, ".kube", "config") - } else { - fmt.Println("-------请输入 -k 参数获取kubeconfig信息") - return errors.New("NO_KUBECONFIG") - } - } - fmt.Println("----------------------------------------->开始卸载服务") - releases, err := ioutil.ReadDir(depPath + "/quanxiang_charts") - if err != nil { - return err - } - for _, release := range releases { - if release.IsDir() { - fmt.Println("--------->卸载" + release.Name() + "服务 \n") - var command string - switch { - case strings.Contains(release.Name(), "builder"): - command = fmt.Sprintf("helm uninstall %s --kubeconfig %s -n builder", release.Name(), kubeconfig) - case strings.Contains(release.Name(), "serving"): - command = fmt.Sprintf("helm uninstall %s --kubeconfig %s -n serving", release.Name(), kubeconfig) - case strings.Contains(release.Name(), "fluent"): - command = fmt.Sprintf("helm uninstall %s --kubeconfig %s -n builder ", release.Name(), kubeconfig) - default: - command = "helm uninstall " + release.Name() + " --kubeconfig " + kubeconfig + " -n " + namespace - } - err := execBash(command) - if err != nil { - return err - } - //fmt.Printf("--------->%s 卸载完成,如果出现Error错误请参照检查 \n", strings.Split(command," ")[2]) - //fmt.Println() - } - } - if uninstallMiddlerware { - fmt.Println("----------------------------------------->开始卸载中间件") - releases, err = ioutil.ReadDir(depPath + "/middleware_deployment") - if err != nil { - return err - } - for _, release := range releases { - if release.IsDir() { - fmt.Println("--------->卸载" + release.Name() + "服务 \n") - var command string - switch { - case strings.Contains(release.Name(), "dapr"): - command = "helm uninstall " + release.Name() + " --kubeconfig " + kubeconfig + " -n dapr-system" - /* - case strings.Contains(release.Name(), "builder"): - command = "helm uninstall " + release.Name() + " --kubeconfig " + kubeconfig + " -n builder" - case strings.Contains(release.Name(), "serving"): - command = "helm uninstall " + release.Name() + " --kubeconfig " + kubeconfig + " -n serving" - case strings.Contains(release.Name(), "fluent"): - command = "helm uninstall " + release.Name() + " --kubeconfig " + kubeconfig + " -n builder" - */ - default: - command = "helm uninstall " + release.Name() + " --kubeconfig " + kubeconfig + " -n " + namespace - } - if skipDapr && strings.Contains(release.Name(), "dapr") { - fmt.Println("跳过Dapr系统的卸载") - } else { - err := execBash(command) - if err != nil { - return err - } - } - - } - } - } - command := "kubectl delete secret rsa -n builder --kubeconfig " + kubeconfig - err = execBash(command) - if err != nil { - fmt.Println(err) - } - command = "kubectl delete secret faas-docker -n serving --kubeconfig " + kubeconfig - err = execBash(command) - if err != nil { - fmt.Println(err) - } - command = "kubectl delete secret faas-docker -n builder" + " --kubeconfig " + kubeconfig - err = execBash(command) - if err != nil { - fmt.Println(err) - } - return nil -} diff --git a/deployment/scripts/init-artery-engine-persona.js b/deployment/scripts/init-artery-engine-persona.js deleted file mode 100644 index 72a3d28..0000000 --- a/deployment/scripts/init-artery-engine-persona.js +++ /dev/null @@ -1,112 +0,0 @@ -const allPackages = [ - { - name: 'all', - label: '所有组件', - version: '1.0.0', - }, - { - name: 'system-components', - label: '系统组件', - version: '1.0.0', - }, - { - name: '@one-for-all/icon', - label: '图标库', - version: '0.6.2', - categories: [ - 'action', - 'alert', - 'av', - 'background', - 'communication', - 'content', - 'device', - 'editor', - 'file', - 'hardware', - 'home', - 'image', - 'maps', - 'mobile', - 'navigation', - 'notification', - 'places', - 'qxp_ui', - 'social', - 'toggle', - ], - }, - { - name: '@one-for-all/headless-ui', - label: 'headless-ui', - version: '0.8.3', - categories: [ - '基础组件', - '表单组件', - '高级组件', - ], - }, -]; - -const headlessUIPropsSpecURL = 'https://ofapkg.pek3b.qingstor.com/@one-for-all/headless-ui@latest/props-spec.json'; -const headlessUIManifestURL = 'https://ofapkg.pek3b.qingstor.com/@one-for-all/headless-ui@latest/manifest.json'; -const iconManifestURL = 'https://ofapkg.pek3b.qingstor.com/artery-engine-person-initialize-json/one-for-all-icon-manifest.json'; -const iconPropsPSpecURL = 'https://ofapkg.pek3b.qingstor.com/artery-engine-person-initialize-json/one-for-all-icon-props-spec.json'; -const systemComponentManifestURL = 'https://ofapkg.pek3b.qingstor.com/artery-engine-person-initialize-json/system-component-manifest.json'; -const systemComponentPropsSpecURL = 'https://ofapkg.pek3b.qingstor.com/artery-engine-person-initialize-json/system-component-props-spec.json'; - -Promise.all([ - fetch(headlessUIPropsSpecURL).then((res) => res.text()), - fetch(headlessUIManifestURL).then((res) => res.text()), - fetch(iconManifestURL).then((res) => res.text()), - fetch(iconPropsPSpecURL).then((res) => res.text()), - fetch(systemComponentManifestURL).then((res) => res.text()), - fetch(systemComponentPropsSpecURL).then((res) => res.text()), -]).then(([ - headlessUIPropsSpec, - headlessUIManifest, - iconManifest, - iconPropsPSpec, - systemComponentManifest, - systemComponentPropsSpec, -]) => { - const keys = [ - { - key: 'PACKAGE_PROPS_SPEC:@one-for-all/headless-ui', - version: '0.8.3', - value: headlessUIPropsSpec, - }, - { - key: 'PACKAGE_MANIFEST:@one-for-all/headless-ui', - version: '0.8.3', - value: headlessUIManifest, - }, - { - key: 'PACKAGE_MANIFEST:@one-for-all/icon', - version: '0.6.2', - value: iconManifest, - }, - { - key: 'PACKAGE_PROPS_SPEC:@one-for-all/icon', - version: '0.6.2', - value: iconPropsPSpec, - }, - { - key: 'PACKAGE_MANIFEST:system-components', - version: '1.0.0', - value: systemComponentManifest, - }, - { - key: 'PACKAGE_PROPS_SPEC:system-components', - version: '1.0.0', - value: systemComponentPropsSpec, - }, - { - key: 'PACKAGES', - version: '1.0.0', - value: JSON.stringify(allPackages), - }, - ]; - - return window.__httpClient('/api/v1/persona/batchSetValue', { keys }); -}).then(() => console.log('artery-engine persona initialized')); diff --git a/deployment/scripts/init_nav.js b/deployment/scripts/init_nav.js deleted file mode 100644 index 9cf3e0f..0000000 --- a/deployment/scripts/init_nav.js +++ /dev/null @@ -1,78 +0,0 @@ -const NAV_LIST = [ - { - "id": "app_views", - "title": "应用视图", - "icon": "view", - "children": [ - { - "id": "views", - "title": "页面管理", - "icon": "note_detail_duotone" - }, - { - "id": "view_layout", - "title": "母版管理", - "icon": "row_top_duotone" - }, - { - "id": "app_nav", - "title": "应用导航", - "icon": "tab_duotone" - } - ] - }, - { - "id": "modal_api", - "title": "数据管理", - "icon": "gateway", - "children": [ - { - "id": "data_models", - "title": "数据模型管理", - "icon": "database" - }, - { - "id": "api_proxy", - "title": "第三方 API 代理", - "icon": "api_outside" - }, - { - "id": "orchestration_api", - "title": "API 编排管理", - "icon": "api_arrange" - }, - { - "id": "faas", - "title": "FaaS 函数管理", - "icon": "faas_control" - }, - { - "id": "key_api", - "title": "API 密钥管理", - "icon": "api_key" - }, - { - "id": "file_api", - "title": "API 文档", - "icon": "api_inner" - } - ] - }, - { - "id": "setting_flow", - "title": "工作流", - "icon": "data_model" - }, - { - "id": "app_control", - "title": "访问控制", - "icon": "role" - }, - { - "id": "base_info", - "title": "应用设置", - "icon": "app_setting" - } -] - -__httpClient('/api/v1/persona/batchSetValue', { keys: [{ key: 'PORTAL_APPLICATION_SIDE_NAV', version: '0.1.0', value: JSON.stringify(NAV_LIST) }] }) \ No newline at end of file From 945fc83dd71eb5917ab5ce0b7d70e58061000abd Mon Sep 17 00:00:00 2001 From: kevin Date: Mon, 27 Mar 2023 19:03:08 +0800 Subject: [PATCH 2/4] fix: add init job and fix issues --- README.md | 148 +- deployment/charts/mysql/.helmignore | 23 +- deployment/charts/mysql/Chart.lock | 6 - deployment/charts/mysql/Chart.yaml | 35 +- deployment/charts/mysql/README.md | 663 ++---- .../charts/mysql/charts/common/Chart.yaml | 23 - .../charts/mysql/charts/common/README.md | 351 --- .../charts/common/templates/_affinities.tpl | 106 - .../charts/common/templates/_capabilities.tpl | 154 -- .../mysql/charts/common/templates/_errors.tpl | 23 - .../mysql/charts/common/templates/_images.tpl | 76 - .../charts/common/templates/_ingress.tpl | 68 - .../mysql/charts/common/templates/_labels.tpl | 18 - .../mysql/charts/common/templates/_names.tpl | 66 - .../charts/common/templates/_secrets.tpl | 165 -- .../charts/common/templates/_storage.tpl | 23 - .../charts/common/templates/_tplvalues.tpl | 13 - .../mysql/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/mysql/charts/common/values.yaml | 5 - deployment/charts/mysql/templates/NOTES.txt | 87 +- .../charts/mysql/templates/_helpers.tpl | 160 +- .../configurationFiles-configmap.yaml | 12 + .../charts/mysql/templates/deployment.yaml | 259 +++ .../charts/mysql/templates/extra-list.yaml | 4 - .../initializationFiles-configmap.yaml | 12 + .../charts/mysql/templates/metrics-svc.yaml | 29 - .../charts/mysql/templates/networkpolicy.yaml | 40 - .../mysql/templates/primary/configmap.yaml | 18 - .../primary/initialization-configmap.yaml | 17 - .../charts/mysql/templates/primary/pdb.yaml | 25 - .../mysql/templates/primary/statefulset.yaml | 382 ---- .../mysql/templates/primary/svc-headless.yaml | 29 - .../charts/mysql/templates/primary/svc.yaml | 52 - .../mysql/templates/prometheusrule.yaml | 22 - deployment/charts/mysql/templates/pvc.yaml | 29 + deployment/charts/mysql/templates/role.yaml | 24 - .../charts/mysql/templates/rolebinding.yaml | 21 - .../mysql/templates/secondary/configmap.yaml | 18 - .../charts/mysql/templates/secondary/pdb.yaml | 25 - .../templates/secondary/statefulset.yaml | 363 ---- .../templates/secondary/svc-headless.yaml | 31 - .../charts/mysql/templates/secondary/svc.yaml | 54 - .../charts/mysql/templates/secrets.yaml | 60 +- .../mysql/templates/serviceaccount.yaml | 24 +- .../mysql/templates/servicemonitor.yaml | 51 +- deployment/charts/mysql/templates/svc.yaml | 42 + .../mysql/templates/tests/test-configmap.yaml | 23 + .../charts/mysql/templates/tests/test.yaml | 59 + deployment/charts/mysql/values.schema.json | 195 -- deployment/charts/mysql/values.yaml | 1380 ++---------- deployment/charts/nginx-ingress/.helmignore | 2 + deployment/charts/nginx-ingress/Chart.yaml | 17 + deployment/charts/nginx-ingress/README.md | 274 +++ .../crds/appprotect.f5.com_aplogconfs.yaml | 80 + .../crds/appprotect.f5.com_appolicies.yaml | 1903 +++++++++++++++++ .../crds/appprotect.f5.com_apusersigs.yaml | 93 + .../appprotectdos.f5.com_apdoslogconfs.yaml | 68 + .../appprotectdos.f5.com_apdospolicy.yaml | 68 + ...otectdos.f5.com_dosprotectedresources.yaml | 81 + .../externaldns.nginx.org_dnsendpoints.yaml | 85 + .../k8s.nginx.org_globalconfigurations.yaml | 50 + .../crds/k8s.nginx.org_policies.yaml | 294 +++ .../crds/k8s.nginx.org_transportservers.yaml | 151 ++ .../k8s.nginx.org_virtualserverroutes.yaml | 635 ++++++ .../crds/k8s.nginx.org_virtualservers.yaml | 715 +++++++ .../charts/nginx-ingress/templates/NOTES.txt | 1 + .../nginx-ingress/templates/_helpers.tpl | 93 + .../templates/controller-configmap.yaml | 17 + .../templates/controller-daemonset.yaml | 243 +++ .../templates/controller-deployment.yaml | 246 +++ .../controller-globalconfiguration.yaml | 11 + .../templates/controller-hpa.yaml | 37 + .../templates/controller-ingress-class.yaml | 10 + .../controller-leader-election-configmap.yaml | 11 + .../templates/controller-secret.yaml | 13 + .../templates/controller-service.yaml | 69 + .../templates/controller-serviceaccount.yaml | 16 + .../templates/controller-servicemonitor.yaml | 15 + .../templates/controller-wildcard-secret.yaml | 13 + .../charts/nginx-ingress/templates/rbac.yaml | 204 ++ .../charts/nginx-ingress/values-icp.yaml | 16 + .../charts/nginx-ingress/values-nsm.yaml | 5 + .../charts/nginx-ingress/values-plus.yaml | 5 + .../charts/nginx-ingress/values.schema.json | 1686 +++++++++++++++ deployment/charts/nginx-ingress/values.yaml | 455 ++++ deployment/charts/quanxiang/Chart.lock | 12 +- deployment/charts/quanxiang/Chart.yaml | 20 +- .../appcenter/templates/deployment.yaml | 4 +- .../quanxiang/charts/appcenter/values.yaml | 10 +- .../builder/templates/create-namespace.yaml | 11 + .../charts/elasticsearch-17.9.24.tgz | Bin 93754 -> 93748 bytes .../charts/fileserver/templates/ingress.yaml | 2 +- .../quanxiang/charts/fileserver/values.yaml | 4 +- .../quanxiang/charts/fluent-bit-2.10.3.tgz | Bin 14321 -> 14323 bytes .../charts}/fluent-bit/Chart.yaml | 0 .../charts}/fluent-bit/README.md | 0 .../charts}/fluent-bit/templates/_helpers.tpl | 0 .../fluent-bit/templates/cluster-role.yaml | 0 .../templates/cluster-rolebinding.yaml | 0 .../fluent-bit/templates/daemonset.yaml | 2 +- .../templates/fluent-bit-secret.yaml | 4 +- .../charts}/fluent-bit/templates/psp.yaml | 0 .../charts}/fluent-bit/templates/secret.yaml | 0 .../charts}/fluent-bit/templates/service.yaml | 0 .../fluent-bit/templates/serviceaccount.yaml | 0 .../fluent-bit/templates/servicemonitor.yaml | 0 .../templates/tests/test-configmap.yaml | 0 .../fluent-bit/templates/tests/test.yaml | 0 .../charts}/fluent-bit/values.yaml | 5 +- .../charts/form/templates/configmap.yaml | 2 +- .../charts/init-job}/.helmignore | 0 .../quanxiang/charts/init-job/Chart.yaml | 24 + .../charts/init-job/templates/_helpers.tpl | 56 + .../charts/init-job/templates/initdb_job.yaml | 32 + .../quanxiang/charts/init-job/values.yaml | 9 + .../charts/quanxiang/charts/kafka-20.0.2.tgz | Bin 115196 -> 115187 bytes .../charts/quanxiang/charts/minio-5.0.33.tgz | Bin 19289 -> 19283 bytes .../quanxiang/charts/mongodb-13.6.2.tgz | Bin 74455 -> 74457 bytes .../charts/quanxiang/charts/mysql-1.6.9.tgz | Bin 0 -> 11584 bytes .../charts/quanxiang/charts/mysql-9.4.6.tgz | Bin 45761 -> 0 bytes .../quanxiang/charts/nginx-ingress-0.16.1.tgz | Bin 0 -> 40188 bytes .../charts/polyapi/templates/deployment.yaml | 8 + .../charts/polyapi/templates/ingress.yaml | 2 +- .../charts/polygate/templates/ingress.yaml | 2 +- .../qxp-web-home/templates/ingress.yaml | 29 + .../qxp-web-portal/templates/ingress.yml | 4 +- .../qxp-web-vendors/templates/ingress.yml | 2 +- .../quanxiang/charts/redis-cluster-7.1.0.tgz | Bin 97445 -> 97442 bytes .../serving/templates/create-namespace.yaml | 11 + .../web-process/templates/deployment.yaml | 12 +- deployment/charts/quanxiang/values.yaml | 183 +- 139 files changed, 9087 insertions(+), 5271 deletions(-) delete mode 100644 deployment/charts/mysql/Chart.lock mode change 100644 => 100755 deployment/charts/mysql/Chart.yaml mode change 100644 => 100755 deployment/charts/mysql/README.md delete mode 100644 deployment/charts/mysql/charts/common/Chart.yaml delete mode 100644 deployment/charts/mysql/charts/common/README.md delete mode 100644 deployment/charts/mysql/charts/common/templates/_affinities.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/_capabilities.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/_errors.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/_images.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/_ingress.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/_labels.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/_names.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/_secrets.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/_storage.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/_tplvalues.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/_utils.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/_warnings.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/validations/_cassandra.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/validations/_mariadb.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/validations/_mongodb.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/validations/_mysql.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/validations/_postgresql.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/validations/_redis.tpl delete mode 100644 deployment/charts/mysql/charts/common/templates/validations/_validations.tpl delete mode 100644 deployment/charts/mysql/charts/common/values.yaml create mode 100644 deployment/charts/mysql/templates/configurationFiles-configmap.yaml create mode 100644 deployment/charts/mysql/templates/deployment.yaml delete mode 100644 deployment/charts/mysql/templates/extra-list.yaml create mode 100644 deployment/charts/mysql/templates/initializationFiles-configmap.yaml delete mode 100644 deployment/charts/mysql/templates/metrics-svc.yaml delete mode 100644 deployment/charts/mysql/templates/networkpolicy.yaml delete mode 100644 deployment/charts/mysql/templates/primary/configmap.yaml delete mode 100644 deployment/charts/mysql/templates/primary/initialization-configmap.yaml delete mode 100644 deployment/charts/mysql/templates/primary/pdb.yaml delete mode 100644 deployment/charts/mysql/templates/primary/statefulset.yaml delete mode 100644 deployment/charts/mysql/templates/primary/svc-headless.yaml delete mode 100644 deployment/charts/mysql/templates/primary/svc.yaml delete mode 100644 deployment/charts/mysql/templates/prometheusrule.yaml create mode 100644 deployment/charts/mysql/templates/pvc.yaml delete mode 100644 deployment/charts/mysql/templates/role.yaml delete mode 100644 deployment/charts/mysql/templates/rolebinding.yaml delete mode 100644 deployment/charts/mysql/templates/secondary/configmap.yaml delete mode 100644 deployment/charts/mysql/templates/secondary/pdb.yaml delete mode 100644 deployment/charts/mysql/templates/secondary/statefulset.yaml delete mode 100644 deployment/charts/mysql/templates/secondary/svc-headless.yaml delete mode 100644 deployment/charts/mysql/templates/secondary/svc.yaml mode change 100644 => 100755 deployment/charts/mysql/templates/secrets.yaml create mode 100644 deployment/charts/mysql/templates/svc.yaml create mode 100644 deployment/charts/mysql/templates/tests/test-configmap.yaml create mode 100644 deployment/charts/mysql/templates/tests/test.yaml delete mode 100644 deployment/charts/mysql/values.schema.json create mode 100644 deployment/charts/nginx-ingress/.helmignore create mode 100644 deployment/charts/nginx-ingress/Chart.yaml create mode 100644 deployment/charts/nginx-ingress/README.md create mode 100644 deployment/charts/nginx-ingress/crds/appprotect.f5.com_aplogconfs.yaml create mode 100644 deployment/charts/nginx-ingress/crds/appprotect.f5.com_appolicies.yaml create mode 100644 deployment/charts/nginx-ingress/crds/appprotect.f5.com_apusersigs.yaml create mode 100644 deployment/charts/nginx-ingress/crds/appprotectdos.f5.com_apdoslogconfs.yaml create mode 100644 deployment/charts/nginx-ingress/crds/appprotectdos.f5.com_apdospolicy.yaml create mode 100644 deployment/charts/nginx-ingress/crds/appprotectdos.f5.com_dosprotectedresources.yaml create mode 100644 deployment/charts/nginx-ingress/crds/externaldns.nginx.org_dnsendpoints.yaml create mode 100644 deployment/charts/nginx-ingress/crds/k8s.nginx.org_globalconfigurations.yaml create mode 100644 deployment/charts/nginx-ingress/crds/k8s.nginx.org_policies.yaml create mode 100644 deployment/charts/nginx-ingress/crds/k8s.nginx.org_transportservers.yaml create mode 100644 deployment/charts/nginx-ingress/crds/k8s.nginx.org_virtualserverroutes.yaml create mode 100644 deployment/charts/nginx-ingress/crds/k8s.nginx.org_virtualservers.yaml create mode 100644 deployment/charts/nginx-ingress/templates/NOTES.txt create mode 100644 deployment/charts/nginx-ingress/templates/_helpers.tpl create mode 100644 deployment/charts/nginx-ingress/templates/controller-configmap.yaml create mode 100644 deployment/charts/nginx-ingress/templates/controller-daemonset.yaml create mode 100644 deployment/charts/nginx-ingress/templates/controller-deployment.yaml create mode 100644 deployment/charts/nginx-ingress/templates/controller-globalconfiguration.yaml create mode 100644 deployment/charts/nginx-ingress/templates/controller-hpa.yaml create mode 100644 deployment/charts/nginx-ingress/templates/controller-ingress-class.yaml create mode 100644 deployment/charts/nginx-ingress/templates/controller-leader-election-configmap.yaml create mode 100644 deployment/charts/nginx-ingress/templates/controller-secret.yaml create mode 100644 deployment/charts/nginx-ingress/templates/controller-service.yaml create mode 100644 deployment/charts/nginx-ingress/templates/controller-serviceaccount.yaml create mode 100644 deployment/charts/nginx-ingress/templates/controller-servicemonitor.yaml create mode 100644 deployment/charts/nginx-ingress/templates/controller-wildcard-secret.yaml create mode 100644 deployment/charts/nginx-ingress/templates/rbac.yaml create mode 100644 deployment/charts/nginx-ingress/values-icp.yaml create mode 100644 deployment/charts/nginx-ingress/values-nsm.yaml create mode 100644 deployment/charts/nginx-ingress/values-plus.yaml create mode 100644 deployment/charts/nginx-ingress/values.schema.json create mode 100644 deployment/charts/nginx-ingress/values.yaml create mode 100644 deployment/charts/quanxiang/charts/builder/templates/create-namespace.yaml rename deployment/charts/{ => quanxiang/charts}/fluent-bit/Chart.yaml (100%) rename deployment/charts/{ => quanxiang/charts}/fluent-bit/README.md (100%) rename deployment/charts/{ => quanxiang/charts}/fluent-bit/templates/_helpers.tpl (100%) rename deployment/charts/{ => quanxiang/charts}/fluent-bit/templates/cluster-role.yaml (100%) rename deployment/charts/{ => quanxiang/charts}/fluent-bit/templates/cluster-rolebinding.yaml (100%) rename deployment/charts/{ => quanxiang/charts}/fluent-bit/templates/daemonset.yaml (98%) rename deployment/charts/{ => quanxiang/charts}/fluent-bit/templates/fluent-bit-secret.yaml (94%) rename deployment/charts/{ => quanxiang/charts}/fluent-bit/templates/psp.yaml (100%) rename deployment/charts/{ => quanxiang/charts}/fluent-bit/templates/secret.yaml (100%) rename deployment/charts/{ => quanxiang/charts}/fluent-bit/templates/service.yaml (100%) rename deployment/charts/{ => quanxiang/charts}/fluent-bit/templates/serviceaccount.yaml (100%) rename deployment/charts/{ => quanxiang/charts}/fluent-bit/templates/servicemonitor.yaml (100%) rename deployment/charts/{ => quanxiang/charts}/fluent-bit/templates/tests/test-configmap.yaml (100%) rename deployment/charts/{ => quanxiang/charts}/fluent-bit/templates/tests/test.yaml (100%) rename deployment/charts/{ => quanxiang/charts}/fluent-bit/values.yaml (99%) rename deployment/charts/{mysql/charts/common => quanxiang/charts/init-job}/.helmignore (100%) create mode 100644 deployment/charts/quanxiang/charts/init-job/Chart.yaml create mode 100644 deployment/charts/quanxiang/charts/init-job/templates/_helpers.tpl create mode 100644 deployment/charts/quanxiang/charts/init-job/templates/initdb_job.yaml create mode 100644 deployment/charts/quanxiang/charts/init-job/values.yaml create mode 100644 deployment/charts/quanxiang/charts/mysql-1.6.9.tgz delete mode 100644 deployment/charts/quanxiang/charts/mysql-9.4.6.tgz create mode 100644 deployment/charts/quanxiang/charts/nginx-ingress-0.16.1.tgz create mode 100644 deployment/charts/quanxiang/charts/qxp-web-home/templates/ingress.yaml create mode 100644 deployment/charts/quanxiang/charts/serving/templates/create-namespace.yaml diff --git a/README.md b/README.md index bb27b1c..d081a9d 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ QuanXiang builds a low-code ecosystem around application design, development, de QuanXiang uses a loosely-coupled architecture that separates the frontend from the backend. It provides a plug-and-play, microservices architecture and embraces the diversity of languages and developer frameworks. The platform is divided into: application layer, docking layer, data processing layer and basic layer. -![architecture_en](/doc/images/architecture_en.png) +![architecture_en](./doc/images/architecture_en.png) @@ -106,9 +106,21 @@ QuanXiang privodes a deployment tool, which can help user to quckly deploy QuanX - Kubernetes cluster environment v1.21.* - OpenFunction v0.6.0 +- MetalLb v0.13.7 (*optional*) ### Deploy QuanXiang on KubeShpere(recommend) +#### Prerequisite + +Before deploying QuanXiang, below options are required in local environment: + +- Accessible KubeSphere cluster. +- 'kubectl' is installed on local. refer [kubectl installation](https://kubernetes.io/docs/tasks/tools/) to install kubectl. +- Kubeconfig is configured. refer below steps to configure kubeconfig + - Get QKE kubeconfig from QingCloud console. + - For KubeSphere kubeconfig, refer to [documentation](https://kubernetes.io/docs/tasks/tools/) or ask [community](https://github.com/kubesphere) for more help. +- Helm3 is required. refer [helm3 installation](https://helm.sh/docs/intro/install/) to install helm3. + #### Step 1. Deploy KubeSphere and Openfunction ##### KubeSphere @@ -130,42 +142,66 @@ KubeSphere cluster requirments: > **Notice** > -> Scale nodes' resources to double and use PaaS that privode by cloud vendors, if you want to use QuanxiangCloud as production. +> Scale nodes' resources to double and use PaaS that privode by cloud vendors, if you want to use QuanXiang as production. +- Deploy OpenFunction with helm: +``` +kubectl create namespace openfunction +helm repo add openfunction https://openfunction.github.io/charts/ +helm update +helm install openfunction openfunction/openfunction --version 0.1.0 -n openfunction +``` -#### Step 2. QuanXiang installation +#### Step 2 Deploy MetalLB (Optional) -##### Prerequisite +Persistence IP address is recommended, that is easily to access QuanXiang web site. Before you deploy MetalLB, you should prepare several IP addresses which should be available. Refer [official documentation](https://metallb.universe.tf/installation/) to more information about installation. -Before deploying QuanXiang, below options are required in local environment: +- Deploy MetalLB with helm: -- Accessible KubeSphere cluster. -- 'kubectl' is installed on local. refer [kubectl installation](https://kubernetes.io/docs/tasks/tools/) to install kubectl. -- Kubeconfig is configured. refer below steps to configure kubeconfig - - Get QKE kubeconfig from QingCloud console. - - For KubeSphere kubeconfig, refer to [documentation](https://kubernetes.io/docs/tasks/tools/) or ask [community](https://github.com/kubesphere) for more help. -- Helm3 is required. refer [helm3 installation](https://helm.sh/docs/intro/install/) to install helm3. +``` +helm repo add metallb https://metallb.github.io/metallb +helm repo update +helm install metallb metallb/metallb -n metallb-system --create-namespace +``` -##### Download release +- Assign IP pool to Kubernetes from file ip-pool.yaml, + +``` +apiVersion: metallb.io/v1beta1 +kind: IPAddressPool +metadata: + name: lowcode + namespace: metallb-system +spec: + addresses: + - 192.168.208.190-192.168.208.195 # replace this to your ips +``` + +>**Notice** +> +>Those IP address must be accessable and available to use. +> +> + +- Apply the IP Pools by "kubectl apply". + +``` +kubectl apply -f ip-pool.yaml +``` + +#### Step 2. QuanXiang installation -You can download the [release version](https://github.com/quanxiang-cloud/quanxiang/releases/tag/v1.1.0) directly. **QuanXiang privodes various architecture package.** +**Helm Charts installation is enabled after v2.0.0.** -##### Build from source code +##### Download release -To build QianXiang deployment tool, that golang 1.16 is needed and special correct GOOS, GOARCH. Example command with Linux and amd64. +You can download the [release version](https://github.com/quanxiang-cloud/quanxiang/releases/tag/v1.1.0) directly or clone the source code from github. ```bash git clone https://github.com/quanxiang-cloud/quanxiang.git - cd quanxiang/deployment - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o installApp main.go ``` -> **Notice** -> -> - GOOS: darwin, Linux, Windows, FreeBSD etc. -> - GOARCH: amd64, 386, arm etc. - #### Deploy QuanXiang QuanxiangCloud deployment tool support production and demo: @@ -175,54 +211,54 @@ QuanxiangCloud deployment tool support production and demo: ##### Configurations -For production, you cat set `enable` to `false` to disable middle services in configuration file `configs/configs.yml` . refer to notes in configuration file for more details. +For production, you cat set `enable` to `false` to disable middle services in configuration file `quanxiang/values.yaml` . refer to notes in values file for more details. ```bash - vim configs/configs.yml - #Middleware Services 中间件服务 - mysql: - enabled: true - rootPassword: qxp1234 #It is required to set the root user password if enabled equal to true 设置root用户密码 enabled为true时必填 - redis: - enabled: true - password: cXhwMTIzNA== #The password here is the base64 code of the password. For example, the base64 code of qxp1234 is cxhwmjm0cg== 这里的password为密码的base64编码,比如qxp1234的base64编码为cXhwMjM0Cg== - kafka: +# Default values for quanxiang. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +#replicaCount: 1 + +global: + namespace: "" + domain: example.com # replace value to your domain. 修改成您自己的域名。 + websocket_hostname: ws.example.com # socket server访问地址 + home_hostname: home.example.com # 用户端访问地址 + portal_hostname: portal.example.com # 管理端访问地址 + vendor: + protocol: http # 前端渲染配置访问协议。 + hostname: vendors.example.com # 前端渲染配置访问地址。 + port: 80 # 前端渲染配置端口。 + faas: + enabled: true # 是否安装faas。 + loadBalancer: &lb + loadBalancerIP: '192.168.208.190' # DONNOT CHAGE &lbIP, 不要修改 &lbIP ---此处填写LB的可用地址,如果使用了MetalLB,在定义的IP pool里的可用地址。 + +hostAliases: &hostAliases + enabled: true # 没有可用的DNS服务做解析时,需要将此处设置为true,配置容器内hosts文件。 + <<: *lb # DONNOT CHAGE THIS LINE, 不要修改此行 + hostnames: + - 'qxp-static.fs.example.com' + - 'default.fs.example.com' ..... ``` ##### Installation -Run `installApp` to install the trial version: +Run `helm install` to install the trial version: ```bash -./installApp start -k ~/.kube/config -i -n lowcode +cd quanxiang/deployment/charts +helm install lowcode -n lowcode ./quanxiang --create-namespace --timeout 1800s ``` -Parameters description: - -| parameter | purpose | Description | -| -------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| -c/--configfile | relative or absolute path of the configuration file | Indicates the absolute or relative path of the current project configs / configs.yml | -| -d/--deploymentFile | absolute or relative path of deployment folder | absolute or relative path to the current project deployment folder | -| -k/--kubeconfig | the profile path than can access to k8s cluster | If the file is in the default location ~ /. Kube / config, you can not specify this parameter. | -| -i/--middlerwareInit | middleware initialization | If specified, perform middleware initialization. | -| -n/--namespace | The namespace in which the service is deployed in the k8s cluster | If not specified, the default namespace is default. | - ##### Uninstall ```bash -./installApp uninstall -k ~/.kube/config -n lowcode +helm uninstall lowcode -n lowcode ``` -Parameters description: - -| parameter | purpose | Description | -| ------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| -d/--deploymentFile | The path to the deployment folder | Absolute or relative path to the current project deployment folder. | -| -k/--kubeconfig | the profile path than can access to k8s cluster | If the file is in the default location ~ /. Kube / config, you can not specify this parameter. | -| -n/--namespace | The namespace in which the service is deployed in the k8s cluster | If not specified, the default namespace is default. | -| -u/--uninstallMiddlerware | Do you need to uninstall the middleware deployed by the tool | If there is no middleware deployed using this tool, you can not add this parameter. When the middleware is loaded and unloaded, it will be reported that there is no such resource and can be ignored. | - #### How to access @@ -235,8 +271,8 @@ Refer [KubeSphere official documentation](https://kubesphere.io/docs/project-adm To access QuanxiangCloud console, you should configure your hosts file or add dns records into dns server. Use default admin user and password `admin@quanxiang.dev/654321a..` to login. -- Go to [http://portal.qxp.com](http://portal.qxp.com/) to access QuanxiangCloud administration console. -- Go to [http://home.qxp.com](http://home.qxp.com/) to access QuanxiangCloud client console. +- Go to http://portal.example.com to access QuanxiangCloud administration console. +- Go to http://home.example.com to access QuanxiangCloud client console. > **Notice** > diff --git a/deployment/charts/mysql/.helmignore b/deployment/charts/mysql/.helmignore index f0c1319..a1c17ae 100644 --- a/deployment/charts/mysql/.helmignore +++ b/deployment/charts/mysql/.helmignore @@ -1,21 +1,2 @@ -# 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 +.git +OWNERS \ No newline at end of file diff --git a/deployment/charts/mysql/Chart.lock b/deployment/charts/mysql/Chart.lock deleted file mode 100644 index 485cbc3..0000000 --- a/deployment/charts/mysql/Chart.lock +++ /dev/null @@ -1,6 +0,0 @@ -dependencies: -- name: common - repository: https://charts.bitnami.com/bitnami - version: 2.2.2 -digest: sha256:49ca75cf23ba5eb7df4becef52580f98c8bd8194eb80368b9d7b875f6eefa8e5 -generated: "2023-01-09T03:04:58.278003695Z" diff --git a/deployment/charts/mysql/Chart.yaml b/deployment/charts/mysql/Chart.yaml old mode 100644 new mode 100755 index 0f7879f..5bca632 --- a/deployment/charts/mysql/Chart.yaml +++ b/deployment/charts/mysql/Chart.yaml @@ -1,28 +1,17 @@ -annotations: - category: Database -apiVersion: v2 -appVersion: 8.0.31 -dependencies: -- name: common - repository: https://charts.bitnami.com/bitnami - tags: - - bitnami-common - version: 2.x.x -description: MySQL is a fast, reliable, scalable, and easy to use open source relational - database system. Designed to handle mission-critical, heavy-load production applications. -home: https://github.com/bitnami/charts/tree/main/bitnami/mysql -icon: https://bitnami.com/assets/stacks/mysql/img/mysql-stack-220x234.png +apiVersion: v1 +name: mysql +version: 1.6.9 +appVersion: 5.7.30 +description: DEPRECATED - Fast, reliable, scalable, and easy to use open-source relational database + system. keywords: - mysql - database - sql -- cluster -- high availability -maintainers: -- name: Bitnami - url: https://github.com/bitnami/charts -name: mysql +home: https://www.mysql.com/ +icon: https://www.mysql.com/common/logos/logo-mysql-170x115.png sources: -- https://github.com/bitnami/containers/tree/main/bitnami/mysql -- https://mysql.com -version: 9.4.6 +- https://github.com/kubernetes/charts +- https://github.com/docker-library/mysql +deprecated: true +engine: gotpl diff --git a/deployment/charts/mysql/README.md b/deployment/charts/mysql/README.md old mode 100644 new mode 100755 index 8efabf0..6923e2a --- a/deployment/charts/mysql/README.md +++ b/deployment/charts/mysql/README.md @@ -1,30 +1,23 @@ - +# ⚠️ Repo Archive Notice -# MySQL packaged by Bitnami +As of Nov 13, 2020, charts in this repo will no longer be updated. +For more information, see the Helm Charts [Deprecation and Archive Notice](https://github.com/helm/charts#%EF%B8%8F-deprecation-and-archive-notice), and [Update](https://helm.sh/blog/charts-repo-deprecation/). -MySQL is a fast, reliable, scalable, and easy to use open source relational database system. Designed to handle mission-critical, heavy-load production applications. +# MySQL -[Overview of MySQL](http://www.mysql.com) +[MySQL](https://MySQL.org) is one of the most popular database servers in the world. Notable users include Wikipedia, Facebook and Google. -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 +## DEPRECATION NOTICE -```bash -$ helm repo add my-repo https://charts.bitnami.com/bitnami -$ helm install my-release my-repo/mysql -``` +This chart is deprecated and no longer supported. ## Introduction -This chart bootstraps a [MySQL](https://github.com/bitnami/containers/tree/main/bitnami/mysql) replication cluster deployment on a [Kubernetes](https://kubernetes.io) cluster using the [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. +This chart bootstraps a single node MySQL deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. ## Prerequisites -- Kubernetes 1.19+ -- Helm 3.2.0+ +- Kubernetes 1.10+ with Beta APIs enabled - PV provisioner support in the underlying infrastructure ## Installing the Chart @@ -32,11 +25,17 @@ Bitnami charts can be used with [Kubeapps](https://kubeapps.dev/) for deployment To install the chart with the release name `my-release`: ```bash -$ helm repo add my-repo https://charts.bitnami.com/bitnami -$ helm install my-release my-repo/mysql +$ helm install --name my-release stable/mysql ``` -These commands deploy MySQL on the Kubernetes cluster in the default configuration. The [Parameters](#parameters) section lists the parameters that can be configured during installation. +The command deploys MySQL on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation. + +By default a random password will be generated for the root user. If you'd like to set your own password change the mysqlRootPassword +in the values.yaml. + +You can retrieve your root password by running the following command. Make sure to replace [YOUR_RELEASE_NAME]: + + printf $(printf '\%o' `kubectl get secret [YOUR_RELEASE_NAME]-mysql -o jsonpath="{.data.mysql-root-password[*]}"`) > **Tip**: List all releases using `helm list` @@ -45,510 +44,212 @@ These commands deploy MySQL on the Kubernetes cluster in the default configurati To uninstall/delete the `my-release` deployment: ```bash -$ helm delete my-release +$ helm delete --purge 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 StorageClass for Persistent Volume(s) | `""` | - - -### Common parameters - -| Name | Description | Value | -| ------------------------ | --------------------------------------------------------------------------------------------------------- | --------------- | -| `kubeVersion` | Force target Kubernetes version (using Helm capabilities if not set) | `""` | -| `nameOverride` | String to partially override common.names.fullname template (will maintain the release name) | `""` | -| `fullnameOverride` | String to fully override common.names.fullname template | `""` | -| `namespaceOverride` | String to fully override common.names.namespace | `""` | -| `clusterDomain` | Cluster domain | `cluster.local` | -| `commonAnnotations` | Common annotations to add to all MySQL resources (sub-charts are not considered). Evaluated as a template | `{}` | -| `commonLabels` | Common labels to add to all MySQL resources (sub-charts are not considered). Evaluated as a template | `{}` | -| `extraDeploy` | Array with extra yaml to deploy with the chart. 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"]` | - - -### MySQL common parameters - -| Name | Description | Value | -| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | -| `image.registry` | MySQL image registry | `docker.io` | -| `image.repository` | MySQL image repository | `bitnami/mysql` | -| `image.tag` | MySQL image tag (immutable tags are recommended) | `8.0.31-debian-11-r30` | -| `image.digest` | MySQL image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | -| `image.pullPolicy` | MySQL 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` | MySQL architecture (`standalone` or `replication`) | `standalone` | -| `auth.rootPassword` | Password for the `root` user. Ignored if existing secret is provided | `""` | -| `auth.createDatabase` | Wheter to create the .Values.auth.database or not | `true` | -| `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` | MySQL replication user | `replicator` | -| `auth.replicationPassword` | MySQL replication user password. Ignored if existing secret is provided | `""` | -| `auth.existingSecret` | Use existing secret for password details. The secret has to contain the keys `mysql-root-password`, `mysql-replication-password` and `mysql-password` | `""` | -| `auth.usePasswordFiles` | Mount credentials as files instead of using an environment variable | `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`) | `""` | - - -### MySQL Primary parameters - -| Name | Description | Value | -| ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------- | -| `primary.name` | Name of the primary database (eg primary, master, leader, ...) | `primary` | -| `primary.command` | Override default container command on MySQL Primary container(s) (useful when using custom images) | `[]` | -| `primary.args` | Override default container args on MySQL Primary container(s) (useful when using custom images) | `[]` | -| `primary.lifecycleHooks` | for the MySQL Primary container(s) to automate configuration before or after startup | `{}` | -| `primary.hostAliases` | Deployment pod host aliases | `[]` | -| `primary.configuration` | Configure MySQL Primary with a custom my.cnf file | `""` | -| `primary.existingConfigmap` | Name of existing ConfigMap with MySQL Primary configuration. | `""` | -| `primary.updateStrategy.type` | Update strategy type for the MySQL primary statefulset | `RollingUpdate` | -| `primary.podAnnotations` | Additional pod annotations for MySQL primary pods | `{}` | -| `primary.podAffinityPreset` | MySQL primary pod affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `primary.podAntiAffinityPreset` | MySQL primary pod anti-affinity preset. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `soft` | -| `primary.nodeAffinityPreset.type` | MySQL primary node affinity preset type. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `primary.nodeAffinityPreset.key` | MySQL primary node label key to match Ignored if `primary.affinity` is set. | `""` | -| `primary.nodeAffinityPreset.values` | MySQL primary node label values to match. Ignored if `primary.affinity` is set. | `[]` | -| `primary.affinity` | Affinity for MySQL primary pods assignment | `{}` | -| `primary.nodeSelector` | Node labels for MySQL primary pods assignment | `{}` | -| `primary.tolerations` | Tolerations for MySQL primary pods assignment | `[]` | -| `primary.priorityClassName` | MySQL primary pods' priorityClassName | `""` | -| `primary.runtimeClassName` | MySQL primary pods' runtimeClassName | `""` | -| `primary.schedulerName` | Name of the k8s scheduler (other than default) | `""` | -| `primary.terminationGracePeriodSeconds` | In seconds, time the given to the MySQL primary pod needs to terminate gracefully | `""` | -| `primary.topologySpreadConstraints` | Topology Spread Constraints for pod assignment | `[]` | -| `primary.podManagementPolicy` | podManagementPolicy to manage scaling operation of MySQL primary pods | `""` | -| `primary.podSecurityContext.enabled` | Enable security context for MySQL primary pods | `true` | -| `primary.podSecurityContext.fsGroup` | Group ID for the mounted volumes' filesystem | `1001` | -| `primary.containerSecurityContext.enabled` | MySQL primary container securityContext | `true` | -| `primary.containerSecurityContext.runAsUser` | User ID for the MySQL primary container | `1001` | -| `primary.containerSecurityContext.runAsNonRoot` | Set MySQL primary container's Security Context runAsNonRoot | `true` | -| `primary.resources.limits` | The resources limits for MySQL primary containers | `{}` | -| `primary.resources.requests` | The requested resources for MySQL primary containers | `{}` | -| `primary.livenessProbe.enabled` | Enable livenessProbe | `true` | -| `primary.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `5` | -| `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 | `5` | -| `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.startupProbe.enabled` | Enable startupProbe | `true` | -| `primary.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `15` | -| `primary.startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | -| `primary.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `1` | -| `primary.startupProbe.failureThreshold` | Failure threshold for startupProbe | `10` | -| `primary.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | -| `primary.customLivenessProbe` | Override default liveness probe for MySQL primary containers | `{}` | -| `primary.customReadinessProbe` | Override default readiness probe for MySQL primary containers | `{}` | -| `primary.customStartupProbe` | Override default startup probe for MySQL primary containers | `{}` | -| `primary.extraFlags` | MySQL primary additional command line flags | `""` | -| `primary.extraEnvVars` | Extra environment variables to be set on MySQL primary containers | `[]` | -| `primary.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for MySQL primary containers | `""` | -| `primary.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for MySQL primary containers | `""` | -| `primary.persistence.enabled` | Enable persistence on MySQL primary replicas using a `PersistentVolumeClaim`. If false, use emptyDir | `true` | -| `primary.persistence.existingClaim` | Name of an existing `PersistentVolumeClaim` for MySQL primary replicas | `""` | -| `primary.persistence.subPath` | The name of a volume's sub path to mount for persistence | `""` | -| `primary.persistence.storageClass` | MySQL primary persistent volume storage Class | `""` | -| `primary.persistence.annotations` | MySQL primary persistent volume claim annotations | `{}` | -| `primary.persistence.accessModes` | MySQL primary persistent volume access Modes | `["ReadWriteOnce"]` | -| `primary.persistence.size` | MySQL 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 MySQL Primary pod(s) | `[]` | -| `primary.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the MySQL Primary container(s) | `[]` | -| `primary.initContainers` | Add additional init containers for the MySQL Primary pod(s) | `[]` | -| `primary.sidecars` | Add additional sidecar containers for the MySQL Primary pod(s) | `[]` | -| `primary.service.type` | MySQL Primary K8s service type | `ClusterIP` | -| `primary.service.ports.mysql` | MySQL Primary K8s service port | `3306` | -| `primary.service.nodePorts.mysql` | MySQL Primary K8s service node port | `""` | -| `primary.service.clusterIP` | MySQL Primary K8s service clusterIP IP | `""` | -| `primary.service.loadBalancerIP` | MySQL Primary loadBalancerIP if service type is `LoadBalancer` | `""` | -| `primary.service.externalTrafficPolicy` | Enable client source IP preservation | `Cluster` | -| `primary.service.loadBalancerSourceRanges` | Addresses that are allowed when MySQL Primary service is LoadBalancer | `[]` | -| `primary.service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | -| `primary.service.annotations` | Additional custom annotations for MySQL primary service | `{}` | -| `primary.service.sessionAffinity` | Session Affinity for Kubernetes service, can be "None" or "ClientIP" | `None` | -| `primary.service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | -| `primary.service.headless.annotations` | Additional custom annotations for headless MySQL primary service. | `{}` | -| `primary.pdb.create` | Enable/disable a Pod Disruption Budget creation for MySQL primary pods | `false` | -| `primary.pdb.minAvailable` | Minimum number/percentage of MySQL primary pods that should remain scheduled | `1` | -| `primary.pdb.maxUnavailable` | Maximum number/percentage of MySQL primary pods that may be made unavailable | `""` | -| `primary.podLabels` | MySQL Primary pod label. If labels are same as commonLabels , this will take precedence | `{}` | - - -### MySQL Secondary parameters - -| Name | Description | Value | -| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------- | -| `secondary.name` | Name of the secondary database (eg secondary, slave, ...) | `secondary` | -| `secondary.replicaCount` | Number of MySQL secondary replicas | `1` | -| `secondary.hostAliases` | Deployment pod host aliases | `[]` | -| `secondary.command` | Override default container command on MySQL Secondary container(s) (useful when using custom images) | `[]` | -| `secondary.args` | Override default container args on MySQL Secondary container(s) (useful when using custom images) | `[]` | -| `secondary.lifecycleHooks` | for the MySQL Secondary container(s) to automate configuration before or after startup | `{}` | -| `secondary.configuration` | Configure MySQL Secondary with a custom my.cnf file | `""` | -| `secondary.existingConfigmap` | Name of existing ConfigMap with MySQL Secondary configuration. | `""` | -| `secondary.updateStrategy.type` | Update strategy type for the MySQL secondary statefulset | `RollingUpdate` | -| `secondary.podAnnotations` | Additional pod annotations for MySQL secondary pods | `{}` | -| `secondary.podAffinityPreset` | MySQL secondary pod affinity preset. Ignored if `secondary.affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `secondary.podAntiAffinityPreset` | MySQL secondary pod anti-affinity preset. Ignored if `secondary.affinity` is set. Allowed values: `soft` or `hard` | `soft` | -| `secondary.nodeAffinityPreset.type` | MySQL secondary node affinity preset type. Ignored if `secondary.affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `secondary.nodeAffinityPreset.key` | MySQL secondary node label key to match Ignored if `secondary.affinity` is set. | `""` | -| `secondary.nodeAffinityPreset.values` | MySQL secondary node label values to match. Ignored if `secondary.affinity` is set. | `[]` | -| `secondary.affinity` | Affinity for MySQL secondary pods assignment | `{}` | -| `secondary.nodeSelector` | Node labels for MySQL secondary pods assignment | `{}` | -| `secondary.tolerations` | Tolerations for MySQL secondary pods assignment | `[]` | -| `secondary.priorityClassName` | MySQL secondary pods' priorityClassName | `""` | -| `secondary.runtimeClassName` | MySQL secondary pods' runtimeClassName | `""` | -| `secondary.schedulerName` | Name of the k8s scheduler (other than default) | `""` | -| `secondary.terminationGracePeriodSeconds` | In seconds, time the given to the MySQL secondary pod needs to terminate gracefully | `""` | -| `secondary.topologySpreadConstraints` | Topology Spread Constraints for pod assignment | `[]` | -| `secondary.podManagementPolicy` | podManagementPolicy to manage scaling operation of MySQL secondary pods | `""` | -| `secondary.podSecurityContext.enabled` | Enable security context for MySQL secondary pods | `true` | -| `secondary.podSecurityContext.fsGroup` | Group ID for the mounted volumes' filesystem | `1001` | -| `secondary.containerSecurityContext.enabled` | MySQL secondary container securityContext | `true` | -| `secondary.containerSecurityContext.runAsUser` | User ID for the MySQL secondary container | `1001` | -| `secondary.containerSecurityContext.runAsNonRoot` | Set MySQL secondary container's Security Context runAsNonRoot | `true` | -| `secondary.resources.limits` | The resources limits for MySQL secondary containers | `{}` | -| `secondary.resources.requests` | The requested resources for MySQL secondary containers | `{}` | -| `secondary.livenessProbe.enabled` | Enable livenessProbe | `true` | -| `secondary.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `5` | -| `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 | `5` | -| `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.startupProbe.enabled` | Enable startupProbe | `true` | -| `secondary.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `15` | -| `secondary.startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | -| `secondary.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `1` | -| `secondary.startupProbe.failureThreshold` | Failure threshold for startupProbe | `15` | -| `secondary.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | -| `secondary.customLivenessProbe` | Override default liveness probe for MySQL secondary containers | `{}` | -| `secondary.customReadinessProbe` | Override default readiness probe for MySQL secondary containers | `{}` | -| `secondary.customStartupProbe` | Override default startup probe for MySQL secondary containers | `{}` | -| `secondary.extraFlags` | MySQL secondary additional command line flags | `""` | -| `secondary.extraEnvVars` | An array to add extra environment variables on MySQL secondary containers | `[]` | -| `secondary.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for MySQL secondary containers | `""` | -| `secondary.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for MySQL secondary containers | `""` | -| `secondary.persistence.enabled` | Enable persistence on MySQL secondary replicas using a `PersistentVolumeClaim` | `true` | -| `secondary.persistence.existingClaim` | Name of an existing `PersistentVolumeClaim` for MySQL secondary replicas | `""` | -| `secondary.persistence.subPath` | The name of a volume's sub path to mount for persistence | `""` | -| `secondary.persistence.storageClass` | MySQL secondary persistent volume storage Class | `""` | -| `secondary.persistence.annotations` | MySQL secondary persistent volume claim annotations | `{}` | -| `secondary.persistence.accessModes` | MySQL secondary persistent volume access Modes | `["ReadWriteOnce"]` | -| `secondary.persistence.size` | MySQL 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 MySQL secondary pod(s) | `[]` | -| `secondary.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the MySQL secondary container(s) | `[]` | -| `secondary.initContainers` | Add additional init containers for the MySQL secondary pod(s) | `[]` | -| `secondary.sidecars` | Add additional sidecar containers for the MySQL secondary pod(s) | `[]` | -| `secondary.service.type` | MySQL secondary Kubernetes service type | `ClusterIP` | -| `secondary.service.ports.mysql` | MySQL secondary Kubernetes service port | `3306` | -| `secondary.service.nodePorts.mysql` | MySQL secondary Kubernetes service node port | `""` | -| `secondary.service.clusterIP` | MySQL secondary Kubernetes service clusterIP IP | `""` | -| `secondary.service.loadBalancerIP` | MySQL secondary loadBalancerIP if service type is `LoadBalancer` | `""` | -| `secondary.service.externalTrafficPolicy` | Enable client source IP preservation | `Cluster` | -| `secondary.service.loadBalancerSourceRanges` | Addresses that are allowed when MySQL secondary service is LoadBalancer | `[]` | -| `secondary.service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | -| `secondary.service.annotations` | Additional custom annotations for MySQL secondary service | `{}` | -| `secondary.service.sessionAffinity` | Session Affinity for Kubernetes service, can be "None" or "ClientIP" | `None` | -| `secondary.service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | -| `secondary.service.headless.annotations` | Additional custom annotations for headless MySQL secondary service. | `{}` | -| `secondary.pdb.create` | Enable/disable a Pod Disruption Budget creation for MySQL secondary pods | `false` | -| `secondary.pdb.minAvailable` | Minimum number/percentage of MySQL secondary pods that should remain scheduled | `1` | -| `secondary.pdb.maxUnavailable` | Maximum number/percentage of MySQL secondary pods that may be made unavailable | `""` | -| `secondary.podLabels` | Additional pod labels for MySQL secondary pods | `{}` | - - -### RBAC parameters - -| Name | Description | Value | -| --------------------------------------------- | -------------------------------------------------------------- | ------- | -| `serviceAccount.create` | Enable the creation of a ServiceAccount for MySQL pods | `true` | -| `serviceAccount.name` | Name of the created ServiceAccount | `""` | -| `serviceAccount.annotations` | Annotations for MySQL Service Account | `{}` | -| `serviceAccount.automountServiceAccountToken` | Automount service account token for the server service account | `true` | -| `rbac.create` | Whether to create & use RBAC resources or not | `false` | -| `rbac.rules` | Custom RBAC rules to set | `[]` | - - -### Network Policy - -| Name | Description | Value | -| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------- | ------- | -| `networkPolicy.enabled` | Enable creation of NetworkPolicy resources | `false` | -| `networkPolicy.allowExternal` | The Policy model to apply. | `true` | -| `networkPolicy.explicitNamespacesSelector` | A Kubernetes LabelSelector to explicitly select namespaces from which ingress traffic could be allowed to MySQL | `{}` | - - -### 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-r70` | -| `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` | Init container volume-permissions resources | `{}` | - - -### 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-r76` | -| `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.service.type` | Kubernetes service type for MySQL Prometheus Exporter | `ClusterIP` | -| `metrics.service.port` | MySQL Prometheus Exporter service port | `9104` | -| `metrics.service.annotations` | Prometheus exporter service annotations | `{}` | -| `metrics.extraArgs.primary` | Extra args to be passed to mysqld_exporter on Primary pods | `[]` | -| `metrics.extraArgs.secondary` | Extra args to be passed to mysqld_exporter on Secondary pods | `[]` | -| `metrics.resources.limits` | The resources limits for MySQL prometheus exporter containers | `{}` | -| `metrics.resources.requests` | The requested resources for MySQL 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` | Specify the namespace in which the serviceMonitor resource will be created | `""` | -| `metrics.serviceMonitor.jobLabel` | The name of the label on the target service to use as the job name in prometheus. | `""` | -| `metrics.serviceMonitor.interval` | Specify the 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.selector` | ServiceMonitor selector labels | `{}` | -| `metrics.serviceMonitor.honorLabels` | Specify honorLabels parameter to add the scrape endpoint | `false` | -| `metrics.serviceMonitor.labels` | Used to pass Labels that are used by the Prometheus installed in your cluster to select Service Monitors to work with | `{}` | -| `metrics.serviceMonitor.annotations` | ServiceMonitor annotations | `{}` | -| `metrics.prometheusRule.enabled` | 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 | `[]` | - - -The above parameters map to the env variables defined in [bitnami/mysql](https://github.com/bitnami/containers/tree/main/bitnami/mysql). For more information please refer to the [bitnami/mysql](https://github.com/bitnami/containers/tree/main/bitnami/mysql) image documentation. +The command removes all the Kubernetes components associated with the chart and deletes the release completely. + +## Configuration + +The following table lists the configurable parameters of the MySQL chart and their default values. + +| Parameter | Description | Default | +| -------------------------------------------- | -------------------------------------------------------------------------------------------- | ---------------------------------------------------- | +| `args` | Additional arguments to pass to the MySQL container. | `[]` | +| `initContainer.resources` | initContainer resource requests/limits | Memory: `10Mi`, CPU: `10m` | +| `image` | `mysql` image repository. | `mysql` | +| `imageTag` | `mysql` image tag. | `5.7.30` | +| `busybox.image` | `busybox` image repository. | `busybox` | +| `busybox.tag` | `busybox` image tag. | `1.32` | +| `testFramework.enabled` | `test-framework` switch. | `true` | +| `testFramework.image` | `test-framework` image repository. | `bats/bats` | +| `testFramework.tag` | `test-framework` image tag. | `1.2.1` | +| `testFramework.imagePullPolicy` | `test-framework` image pull policy. | `IfNotPresent` | +| `testFramework.securityContext` | `test-framework` securityContext | `{}` | +| `imagePullPolicy` | Image pull policy | `IfNotPresent` | +| `existingSecret` | Use Existing secret for Password details | `nil` | +| `extraVolumes` | Additional volumes as a string to be passed to the `tpl` function | | +| `extraVolumeMounts` | Additional volumeMounts as a string to be passed to the `tpl` function | | +| `extraInitContainers` | Additional init containers as a string to be passed to the `tpl` function | | +| `extraEnvVars` | Additional environment variables as a string to be passed to the `tpl` function | | +| `mysqlRootPassword` | Password for the `root` user. Ignored if existing secret is provided | Random 10 characters | +| `mysqlUser` | Username of new user to create. | `nil` | +| `mysqlPassword` | Password for the new user. Ignored if existing secret is provided | Random 10 characters | +| `mysqlDatabase` | Name for new database to create. | `nil` | +| `livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 30 | +| `livenessProbe.periodSeconds` | How often to perform the probe | 10 | +| `livenessProbe.timeoutSeconds` | When the probe times out | 5 | +| `livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed. | 1 | +| `livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 3 | +| `readinessProbe.initialDelaySeconds` | Delay before readiness probe is initiated | 5 | +| `readinessProbe.periodSeconds` | How often to perform the probe | 10 | +| `readinessProbe.timeoutSeconds` | When the probe times out | 1 | +| `readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed. | 1 | +| `readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 3 | +| `schedulerName` | Name of the k8s scheduler (other than default) | `nil` | +| `mysqlx.port.enabled` | Boolean to toggle a port for mysqlx `33060` protocol. | false | +| `persistence.enabled` | Create a volume to store data | true | +| `persistence.size` | Size of persistent volume claim | 8Gi RW | +| `persistence.storageClass` | Type of persistent volume claim | nil | +| `persistence.accessMode` | ReadWriteOnce or ReadOnly | ReadWriteOnce | +| `persistence.existingClaim` | Name of existing persistent volume | `nil` | +| `persistence.subPath` | Subdirectory of the volume to mount | `nil` | +| `persistence.annotations` | Persistent Volume annotations | {} | +| `nodeSelector` | Node labels for pod assignment | {} | +| `affinity` | Affinity rules for pod assignment | {} | +| `tolerations` | Pod taint tolerations for deployment | {} | +| `metrics.enabled` | Start a side-car prometheus exporter | `false` | +| `metrics.image` | Exporter image | `prom/mysqld-exporter` | +| `metrics.imageTag` | Exporter image | `v0.10.0` | +| `metrics.imagePullPolicy` | Exporter image pull policy | `IfNotPresent` | +| `metrics.resources` | Exporter resource requests/limit | `nil` | +| `metrics.livenessProbe.initialDelaySeconds` | Delay before metrics liveness probe is initiated | 15 | +| `metrics.livenessProbe.timeoutSeconds` | When the probe times out | 5 | +| `metrics.readinessProbe.initialDelaySeconds` | Delay before metrics readiness probe is initiated | 5 | +| `metrics.readinessProbe.timeoutSeconds` | When the probe times out | 1 | +| `metrics.flags` | Additional flags for the mysql exporter to use | `[]` | +| `metrics.serviceMonitor.enabled` | Set this to `true` to create ServiceMonitor for Prometheus operator | `false` | +| `metrics.serviceMonitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | `{}` | +| `resources` | CPU/Memory resource requests/limits | Memory: `256Mi`, CPU: `100m` | +| `configurationFiles` | List of mysql configuration files | `nil` | +| `configurationFilesPath` | Path of mysql configuration files | `/etc/mysql/conf.d/` | +| `securityContext.enabled` | Enable security context (mysql pod) | `false` | +| `securityContext.fsGroup` | Group ID for the container (mysql pod) | 999 | +| `securityContext.runAsUser` | User ID for the container (mysql pod) | 999 | +| `service.annotations` | Kubernetes annotations for mysql | {} | +| `service.type` | Kubernetes service type | ClusterIP | +| `service.loadBalancerIP` | LoadBalancer service IP | `""` | +| `serviceAccount.create` | Specifies whether a ServiceAccount should be created | `false` | +| `serviceAccount.name` | The name of the ServiceAccount to create | Generated using the mysql.fullname template | +| `ssl.enabled` | Setup and use SSL for MySQL connections | `false` | +| `ssl.secret` | Name of the secret containing the SSL certificates | mysql-ssl-certs | +| `ssl.certificates[0].name` | Name of the secret containing the SSL certificates | `nil` | +| `ssl.certificates[0].ca` | CA certificate | `nil` | +| `ssl.certificates[0].cert` | Server certificate (public key) | `nil` | +| `ssl.certificates[0].key` | Server key (private key) | `nil` | +| `imagePullSecrets` | Name of Secret resource containing private registry credentials | `nil` | +| `initializationFiles` | List of SQL files which are run after the container started | `nil` | +| `timezone` | Container and mysqld timezone (TZ env) | `nil` (UTC depending on image) | +| `podAnnotations` | Map of annotations to add to the pods | `{}` | +| `podLabels` | Map of labels to add to the pods | `{}` | +| `priorityClassName` | Set pod priorityClassName | `{}` | +| `deploymentAnnotations` | Map of annotations for deployment | `{}` | +| `strategy` | Update strategy policy | `{type: "Recreate"}` | + +Some of the parameters above map to the env variables defined in the [MySQL DockerHub image](https://hub.docker.com/_/mysql/). 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/mysql +$ helm install --name my-release \ + --set mysqlRootPassword=secretpassword,mysqlUser=my-user,mysqlPassword=my-password,mysqlDatabase=my-database \ + stable/mysql ``` -The above command sets the MySQL `root` account password to `secretpassword`. Additionally it creates a database named `app_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. +The above command sets the MySQL `root` account password to `secretpassword`. Additionally it creates a standard database user named `my-user`, with the password `my-password`, who has access to a database named `my-database`. 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/mysql +$ helm install --name my-release -f values.yaml stable/mysql ``` > **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. - -### Use a different MySQL version - -To modify the application version used in this chart, specify a different version of the image using the `image.tag` parameter and/or a different repository using the `image.repository` parameter. Refer to the [chart documentation for more information on these parameters and how to use them with images from a private registry](https://docs.bitnami.com/kubernetes/infrastructure/mysql/configuration/change-image-version/). - -### Customize a new MySQL instance - -The [Bitnami MySQL](https://github.com/bitnami/containers/tree/main/bitnami/mysql) 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`. +## Persistence -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. +The [MySQL](https://hub.docker.com/_/mysql/) image stores the MySQL data and configurations at the `/var/lib/mysql` path of the container. -Refer to the [chart documentation for more information and a usage example](http://docs.bitnami.com/kubernetes/infrastructure/mysql/configuration/customize-new-instance/). +By default a PersistentVolumeClaim is created and mounted into that directory. In order to disable this functionality +you can change the values.yaml to disable persistence and use an emptyDir instead. -### Sidecars and Init Containers +> *"An emptyDir volume is first created when a Pod is assigned to a Node, and exists as long as that Pod is running on that node. When a Pod is removed from a node for any reason, the data in the emptyDir is deleted forever."* -If you have a need for additional containers to run within the same pod as MySQL, you can do so via the `sidecars` config parameter. Simply define your container according to the Kubernetes container spec. +**Notice**: You may need to increase the value of `livenessProbe.initialDelaySeconds` when enabling persistence by using PersistentVolumeClaim from PersistentVolume with varying properties. Since its IO performance has impact on the database initialization performance. The default limit for database initialization is `60` seconds (`livenessProbe.initialDelaySeconds` + `livenessProbe.periodSeconds` * `livenessProbe.failureThreshold`). Once such initialization process takes more time than this limit, kubelet will restart the database container, which will interrupt database initialization then causing persisent data in an unusable state. -```yaml -sidecars: - - name: your-image-name - image: your-image - imagePullPolicy: Always - ports: - - name: portname - containerPort: 1234 -``` +## Custom MySQL configuration files -Similarly, you can add extra init containers using the `initContainers` parameter. +The [MySQL](https://hub.docker.com/_/mysql/) image accepts custom configuration files at the path `/etc/mysql/conf.d`. If you want to use a customized MySQL configuration, you can create your alternative configuration files by passing the file contents on the `configurationFiles` attribute. Note that according to the MySQL documentation only files ending with `.cnf` are loaded. ```yaml -initContainers: - - name: your-image-name - image: your-image - imagePullPolicy: Always - ports: - - name: portname - containerPort: 1234 +configurationFiles: + mysql.cnf: |- + [mysqld] + skip-host-cache + skip-name-resolve + sql-mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION + mysql_custom.cnf: |- + [mysqld] ``` -## Persistence - -The [Bitnami MySQL](https://github.com/bitnami/containers/tree/main/bitnami/mysql) image stores the MySQL data and configurations at the `/bitnami/mysql` 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 for this purpose. - -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/). +## MySQL initialization files -## Network Policy +The [MySQL](https://hub.docker.com/_/mysql/) image accepts *.sh, *.sql and *.sql.gz files at the path `/docker-entrypoint-initdb.d`. +These files are being run exactly once for container initialization and ignored on following container restarts. +If you want to use initialization scripts, you can create initialization files by passing the file contents on the `initializationFiles` attribute. -To enable network policy for MySQL, install [a networking plugin that implements the Kubernetes NetworkPolicy spec](https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy#before-you-begin), and set `networkPolicy.enabled` to `true`. -For Kubernetes v1.5 & v1.6, you must also turn on NetworkPolicy by setting the DefaultDeny namespace annotation. Note: this will enforce policy for _all_ pods in the namespace: - -```console -$ kubectl annotate namespace default "net.beta.kubernetes.io/network-policy={\"ingress\":{\"isolation\":\"DefaultDeny\"}}" +```yaml +initializationFiles: + first-db.sql: |- + CREATE DATABASE IF NOT EXISTS first DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; + second-db.sql: |- + CREATE DATABASE IF NOT EXISTS second DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; ``` -With NetworkPolicy enabled, traffic will be limited to just port 3306. - -For more precise policy, set `networkPolicy.allowExternal=false`. This will only allow pods with the generated client label to connect to MySQL. -This label will be displayed in the output of a successful install. +## SSL -## Pod affinity +This chart supports configuring MySQL to use [encrypted connections](https://dev.mysql.com/doc/refman/5.7/en/encrypted-connections.html) with TLS/SSL certificates provided by the user. This is accomplished by storing the required Certificate Authority file, the server public key certificate, and the server private key as a Kubernetes secret. The SSL options for this chart support the following use cases: -This chart allows you to set your custom affinity using the `XXX.affinity` parameter(s). Find more information about Pod affinity in the [Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity). +* Manage certificate secrets with helm +* Manage certificate secrets outside of helm -As an alternative, you can use the preset configurations for pod affinity, pod anti-affinity, and node affinity available at the [bitnami/common](https://github.com/bitnami/charts/tree/main/bitnami/common#affinities) chart. To do so, set the `XXX.podAffinityPreset`, `XXX.podAntiAffinityPreset`, or `XXX.nodeAffinityPreset` parameters. +## Manage certificate secrets with helm -## Troubleshooting +Include your certificate data in the `ssl.certificates` section. For example: -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/mysql --set auth.rootPassword=[ROOT_PASSWORD] ``` - -| Note: you need to substitute the placeholder _[ROOT_PASSWORD]_ with the value obtained in the installation notes. - -### To 9.0.0 - -This major release renames several values in this chart and adds missing features, in order to be aligned with the rest of the assets in the Bitnami charts repository. - -Affected values: - -- `schedulerName` was renamed as `primary.schedulerName` and `secondary.schedulerName`. -- The way how passwords are handled has been refactored and value `auth.forcePassword` has been removed. Now, the password configuration will have the following priority: - 1. Search for an already existing 'Secret' resource and reuse previous password. - 2. Password provided via the values.yaml - 3. If no secret existed, and no password was provided, the bitnami/mysql chart will set a randomly generated password. -- `primary.service.port` was renamed as `primary.service.ports.mysql`. -- `secondary.service.port` was renamed as `secondary.service.ports.mysql`. -- `primary.service.nodePort` was renamed as `primary.service.nodePorts.mysql`. -- `secondary.service.nodePort` was renamed as `secondary.service.nodePorts.mysql`. -- `primary.updateStrategy` and `secondary.updateStrategy` are now interpreted as an object and not a string. -- Values `primary.rollingUpdatePartition` and `secondary.rollingUpdatePartition` have been removed. In cases were they are needed, they can be set inside `.*updateStrategy`. -- `primary.pdb.enabled` was renamed as `primary.pdb.create`. -- `secondary.pdb.enabled` was renamed as `secondary.pdb.create`. -- `metrics.serviceMonitor.additionalLabels` was renamed as `metrics.serviceMonitor.labels` -- `metrics.serviceMonitor.relabellings` was removed, previously used to configured `metricRelabelings` field. We introduced two new values: `metrics.serviceMonitor.relabelings` and `metrics.serviceMonitor.metricRelabelings` that can be used to configured the serviceMonitor homonimous field. - -### 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. - - Credentials parameters are reorganized under the `auth` parameter. - - `replication.enabled` parameter is deprecated in favor of `architecture` parameter that accepts two values: `standalone` and `replication`. -- 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 MySQL 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://dev.mysql.com/doc/refman/8.0/en/mysqldump.html). - - 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 `mysql`: - -```bash -$ helm install mysql my-repo/mysql --set auth.rootPassword=[ROOT_PASSWORD] --set primary.persistence.existingClaim=[EXISTING_PVC] +ssl: + enabled: false + secret: mysql-ssl-certs + certificates: + - name: mysql-ssl-certs + ca: |- + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + cert: |- + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + key: |- + -----BEGIN RSA PRIVATE KEY----- + ... + -----END RSA PRIVATE KEY----- ``` -| 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 - -[On November 13, 2020, Helm v2 support formally ended](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/mysql/administration/upgrade-helm3/). +> **Note**: Make sure your certificate data has the correct formatting in the values file. -### To 3.0.0 +## Manage certificate secrets outside of helm -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 3.0.0. The following example assumes that the release name is mysql: +1. Ensure the certificate secret exist before installation of this chart. +2. Set the name of the certificate secret in `ssl.secret`. +3. Make sure there are no entries underneath `ssl.certificates`. -```console -$ kubectl delete statefulset mysql-master --cascade=false -$ kubectl delete statefulset mysql-slave --cascade=false +To manually create the certificate secret from local files you can execute: ``` +kubectl create secret generic mysql-ssl-certs \ + --from-file=ca.pem=./ssl/certificate-authority.pem \ + --from-file=server-cert.pem=./ssl/server-public-key.pem \ + --from-file=server-key.pem=./ssl/server-private-key.pem +``` +> **Note**: `ca.pem`, `server-cert.pem`, and `server-key.pem` **must** be used as the key names in this generic secret. -## 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 +If you are using a certificate your configurationFiles must include the three ssl lines under [mysqld] -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 +``` +[mysqld] + ssl-ca=/ssl/ca.pem + ssl-cert=/ssl/server-cert.pem + ssl-key=/ssl/server-key.pem +``` diff --git a/deployment/charts/mysql/charts/common/Chart.yaml b/deployment/charts/mysql/charts/common/Chart.yaml deleted file mode 100644 index f9ba944..0000000 --- a/deployment/charts/mysql/charts/common/Chart.yaml +++ /dev/null @@ -1,23 +0,0 @@ -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/deployment/charts/mysql/charts/common/README.md b/deployment/charts/mysql/charts/common/README.md deleted file mode 100644 index ec43a5f..0000000 --- a/deployment/charts/mysql/charts/common/README.md +++ /dev/null @@ -1,351 +0,0 @@ -# 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/deployment/charts/mysql/charts/common/templates/_affinities.tpl b/deployment/charts/mysql/charts/common/templates/_affinities.tpl deleted file mode 100644 index 81902a6..0000000 --- a/deployment/charts/mysql/charts/common/templates/_affinities.tpl +++ /dev/null @@ -1,106 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/templates/_capabilities.tpl b/deployment/charts/mysql/charts/common/templates/_capabilities.tpl deleted file mode 100644 index 9d9b760..0000000 --- a/deployment/charts/mysql/charts/common/templates/_capabilities.tpl +++ /dev/null @@ -1,154 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/templates/_errors.tpl b/deployment/charts/mysql/charts/common/templates/_errors.tpl deleted file mode 100644 index a79cc2e..0000000 --- a/deployment/charts/mysql/charts/common/templates/_errors.tpl +++ /dev/null @@ -1,23 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/templates/_images.tpl b/deployment/charts/mysql/charts/common/templates/_images.tpl deleted file mode 100644 index 46c659e..0000000 --- a/deployment/charts/mysql/charts/common/templates/_images.tpl +++ /dev/null @@ -1,76 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/templates/_ingress.tpl b/deployment/charts/mysql/charts/common/templates/_ingress.tpl deleted file mode 100644 index 831da9c..0000000 --- a/deployment/charts/mysql/charts/common/templates/_ingress.tpl +++ /dev/null @@ -1,68 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/templates/_labels.tpl b/deployment/charts/mysql/charts/common/templates/_labels.tpl deleted file mode 100644 index 252066c..0000000 --- a/deployment/charts/mysql/charts/common/templates/_labels.tpl +++ /dev/null @@ -1,18 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/templates/_names.tpl b/deployment/charts/mysql/charts/common/templates/_names.tpl deleted file mode 100644 index 617a234..0000000 --- a/deployment/charts/mysql/charts/common/templates/_names.tpl +++ /dev/null @@ -1,66 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/templates/_secrets.tpl b/deployment/charts/mysql/charts/common/templates/_secrets.tpl deleted file mode 100644 index a1708b2..0000000 --- a/deployment/charts/mysql/charts/common/templates/_secrets.tpl +++ /dev/null @@ -1,165 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/templates/_storage.tpl b/deployment/charts/mysql/charts/common/templates/_storage.tpl deleted file mode 100644 index 60e2a84..0000000 --- a/deployment/charts/mysql/charts/common/templates/_storage.tpl +++ /dev/null @@ -1,23 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/templates/_tplvalues.tpl b/deployment/charts/mysql/charts/common/templates/_tplvalues.tpl deleted file mode 100644 index 2db1668..0000000 --- a/deployment/charts/mysql/charts/common/templates/_tplvalues.tpl +++ /dev/null @@ -1,13 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/templates/_utils.tpl b/deployment/charts/mysql/charts/common/templates/_utils.tpl deleted file mode 100644 index b1ead50..0000000 --- a/deployment/charts/mysql/charts/common/templates/_utils.tpl +++ /dev/null @@ -1,62 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/templates/_warnings.tpl b/deployment/charts/mysql/charts/common/templates/_warnings.tpl deleted file mode 100644 index ae10fa4..0000000 --- a/deployment/charts/mysql/charts/common/templates/_warnings.tpl +++ /dev/null @@ -1,14 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/templates/validations/_cassandra.tpl b/deployment/charts/mysql/charts/common/templates/validations/_cassandra.tpl deleted file mode 100644 index ded1ae3..0000000 --- a/deployment/charts/mysql/charts/common/templates/validations/_cassandra.tpl +++ /dev/null @@ -1,72 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/templates/validations/_mariadb.tpl b/deployment/charts/mysql/charts/common/templates/validations/_mariadb.tpl deleted file mode 100644 index b6906ff..0000000 --- a/deployment/charts/mysql/charts/common/templates/validations/_mariadb.tpl +++ /dev/null @@ -1,103 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/templates/validations/_mongodb.tpl b/deployment/charts/mysql/charts/common/templates/validations/_mongodb.tpl deleted file mode 100644 index f820ec1..0000000 --- a/deployment/charts/mysql/charts/common/templates/validations/_mongodb.tpl +++ /dev/null @@ -1,108 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/templates/validations/_mysql.tpl b/deployment/charts/mysql/charts/common/templates/validations/_mysql.tpl deleted file mode 100644 index 74472a0..0000000 --- a/deployment/charts/mysql/charts/common/templates/validations/_mysql.tpl +++ /dev/null @@ -1,103 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/templates/validations/_postgresql.tpl b/deployment/charts/mysql/charts/common/templates/validations/_postgresql.tpl deleted file mode 100644 index 164ec0d..0000000 --- a/deployment/charts/mysql/charts/common/templates/validations/_postgresql.tpl +++ /dev/null @@ -1,129 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/templates/validations/_redis.tpl b/deployment/charts/mysql/charts/common/templates/validations/_redis.tpl deleted file mode 100644 index dcccfc1..0000000 --- a/deployment/charts/mysql/charts/common/templates/validations/_redis.tpl +++ /dev/null @@ -1,76 +0,0 @@ - -{{/* 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/deployment/charts/mysql/charts/common/templates/validations/_validations.tpl b/deployment/charts/mysql/charts/common/templates/validations/_validations.tpl deleted file mode 100644 index 9a814cf..0000000 --- a/deployment/charts/mysql/charts/common/templates/validations/_validations.tpl +++ /dev/null @@ -1,46 +0,0 @@ -{{/* 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/deployment/charts/mysql/charts/common/values.yaml b/deployment/charts/mysql/charts/common/values.yaml deleted file mode 100644 index f2df68e..0000000 --- a/deployment/charts/mysql/charts/common/values.yaml +++ /dev/null @@ -1,5 +0,0 @@ -## bitnami/common -## It is required by CI/CD tools and processes. -## @skip exampleValue -## -exampleValue: common-chart diff --git a/deployment/charts/mysql/templates/NOTES.txt b/deployment/charts/mysql/templates/NOTES.txt index ecf604c..864170c 100644 --- a/deployment/charts/mysql/templates/NOTES.txt +++ b/deployment/charts/mysql/templates/NOTES.txt @@ -1,75 +1,48 @@ -CHART NAME: {{ .Chart.Name }} -CHART VERSION: {{ .Chart.Version }} -APP VERSION: {{ .Chart.AppVersion }} +MySQL can be accessed via port 3306 on the following DNS name from within your cluster: +{{ template "mysql.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local -** 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 {{ include "common.names.namespace" . }} -l app.kubernetes.io/instance={{ .Release.Name }} - -Access the pod you want to debug by executing - - kubectl exec --namespace {{ include "common.names.namespace" . }} -ti -- bash - -In order to replicate the container startup scripts execute this command: - - /opt/bitnami/scripts/mysql/entrypoint.sh /opt/bitnami/scripts/mysql/run.sh - -{{- else }} +{{- if .Values.mysqlx.port.enabled }} +Connection to the X protocol of MySQL can be done via 33060 on the following DNS name from within your cluster: +{{ template "mysql.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local +{{- end }} -Tip: +{{- if .Values.existingSecret }} +If you have not already created the mysql password secret: - Watch the deployment status using the command: kubectl get pods -w --namespace {{ include "common.names.namespace" . }} + kubectl create secret generic {{ .Values.existingSecret }} --namespace {{ .Release.Namespace }} --from-file=./mysql-root-password --from-file=./mysql-password +{{ else }} -Services: +To get your root password run: - echo Primary: {{ include "mysql.primary.fullname" . }}.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }}:{{ .Values.primary.service.ports.mysql }} -{{- if eq .Values.architecture "replication" }} - echo Secondary: {{ include "mysql.secondary.fullname" . }}.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }}:{{ .Values.secondary.service.ports.mysql }} + MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "mysql.fullname" . }} -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo) {{- end }} -Execute the following to get the administrator credentials: - - echo Username: root - MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace {{ include "common.names.namespace" . }} {{ template "mysql.secretName" . }} -o jsonpath="{.data.mysql-root-password}" | base64 -d) - To connect to your database: - 1. Run a pod that you can use as a client: +1. Run an Ubuntu pod that you can use as a client: - kubectl run {{ include "common.names.fullname" . }}-client --rm --tty -i --restart='Never' --image {{ template "mysql.image" . }} --namespace {{ include "common.names.namespace" . }} --env MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD --command -- bash + kubectl run -i --tty ubuntu --image=ubuntu:16.04 --restart=Never -- bash -il - 2. To connect to primary service (read/write): +2. Install the mysql client: - mysql -h {{ include "mysql.primary.fullname" . }}.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }} -uroot -p"$MYSQL_ROOT_PASSWORD" + $ apt-get update && apt-get install mysql-client -y -{{- if eq .Values.architecture "replication" }} +3. Connect using the mysql cli, then provide your password: + $ mysql -h {{ template "mysql.fullname" . }} -p - 3. To connect to secondary service (read-only): +To connect to your database directly from outside the K8s cluster: + {{- if contains "NodePort" .Values.service.type }} + MYSQL_HOST=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath='{.items[0].status.addresses[0].address}') + MYSQL_PORT=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "mysql.fullname" . }} -o jsonpath='{.spec.ports[0].nodePort}') - mysql -h {{ include "mysql.secondary.fullname" . }}.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }} -uroot -p"$MYSQL_ROOT_PASSWORD" -{{- end }} - -{{ if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }} -Note: Since NetworkPolicy is enabled, only pods with label {{ template "common.names.fullname" . }}-client=true" will be able to connect to MySQL. -{{- end }} + {{- else if contains "ClusterIP" .Values.service.type }} + MYSQL_HOST=127.0.0.1 + MYSQL_PORT={{ .Values.service.port }} -{{- if .Values.metrics.enabled }} + # Execute the following command to route the connection: + kubectl port-forward svc/{{ template "mysql.fullname" . }} {{ .Values.service.port }} -To access the MySQL Prometheus metrics from outside the cluster execute the following commands: + {{- end }} - kubectl port-forward --namespace {{ include "common.names.namespace" . }} svc/{{ printf "%s-metrics" (include "common.names.fullname" .) }} {{ .Values.metrics.service.port }}:{{ .Values.metrics.service.port }} & - curl http://127.0.0.1:{{ .Values.metrics.service.port }}/metrics - -{{- end }} - -{{ include "mysql.validateValues" . }} -{{ include "mysql.checkRollingTags" . }} -{{- end }} + mysql -h ${MYSQL_HOST} -P${MYSQL_PORT} -u root -p${MYSQL_ROOT_PASSWORD} + diff --git a/deployment/charts/mysql/templates/_helpers.tpl b/deployment/charts/mysql/templates/_helpers.tpl index 322826f..f108425 100644 --- a/deployment/charts/mysql/templates/_helpers.tpl +++ b/deployment/charts/mysql/templates/_helpers.tpl @@ -1,161 +1,43 @@ {{/* vim: set filetype=mustache: */}} - -{{- define "mysql.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 "mysql.secondary.fullname" -}} -{{- printf "%s-%s" (include "common.names.fullname" .) .Values.secondary.name | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Return the proper MySQL image name -*/}} -{{- define "mysql.image" -}} -{{- include "common.images.image" (dict "imageRoot" .Values.image "global" .Values.global) }} -{{- end -}} - -{{/* -Return the proper metrics image name -*/}} -{{- define "mysql.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) +Expand the name of the chart. */}} -{{- define "mysql.volumePermissions.image" -}} -{{- include "common.images.image" (dict "imageRoot" .Values.volumePermissions.image "global" .Values.global) }} +{{- define "mysql.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} {{- end -}} {{/* -Return the proper Docker Image Registry Secret Names +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 "mysql.imagePullSecrets" -}} -{{- include "common.images.pullSecrets" (dict "images" (list .Values.image .Values.metrics.image .Values.volumePermissions.image) "global" .Values.global) }} -{{- end -}} - -{{/* -Get the initialization scripts ConfigMap name. -*/}} -{{- define "mysql.initdbScriptsCM" -}} -{{- if .Values.initdbScriptsConfigMap -}} - {{- printf "%s" (tpl .Values.initdbScriptsConfigMap $) -}} +{{- define "mysql.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} {{- else -}} - {{- printf "%s-init-scripts" (include "mysql.primary.fullname" .) -}} -{{- end -}} -{{- end -}} - -{{/* - Returns the proper service account name depending if an explicit service account name is set - in the values file. If the name is not set it will default to either mysql.fullname if serviceAccount.create - is true or default otherwise. -*/}} -{{- define "mysql.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 MySQL Primary configuration -*/}} -{{- define "mysql.primary.configmapName" -}} -{{- if .Values.primary.existingConfigmap -}} - {{- printf "%s" (tpl .Values.primary.existingConfigmap $) -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- printf .Release.Name | trunc 63 | trimSuffix "-" -}} {{- else -}} - {{- printf "%s" (include "mysql.primary.fullname" .) -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} {{- end -}} {{- end -}} - -{{/* -Return true if a configmap object should be created for MySQL Secondary -*/}} -{{- define "mysql.primary.createConfigmap" -}} -{{- if and .Values.primary.configuration (not .Values.primary.existingConfigmap) }} - {{- true -}} -{{- else -}} -{{- end -}} {{- end -}} {{/* -Return the configmap with the MySQL Primary configuration -*/}} -{{- define "mysql.secondary.configmapName" -}} -{{- if .Values.secondary.existingConfigmap -}} - {{- printf "%s" (tpl .Values.secondary.existingConfigmap $) -}} -{{- else -}} - {{- printf "%s" (include "mysql.secondary.fullname" .) -}} -{{- end -}} -{{- end -}} - -{{/* -Return true if a configmap object should be created for MySQL Secondary -*/}} -{{- define "mysql.secondary.createConfigmap" -}} -{{- if and (eq .Values.architecture "replication") .Values.secondary.configuration (not .Values.secondary.existingConfigmap) }} - {{- true -}} -{{- else -}} -{{- end -}} -{{- end -}} - -{{/* -Return the secret with MySQL credentials +Generate chart secret name */}} {{- define "mysql.secretName" -}} - {{- if .Values.auth.existingSecret -}} - {{- printf "%s" (tpl .Values.auth.existingSecret $) -}} - {{- else -}} - {{- printf "%s" (include "common.names.fullname" .) -}} - {{- end -}} -{{- end -}} - -{{/* -Return true if a secret object should be created for MySQL -*/}} -{{- define "mysql.createSecret" -}} -{{- if and (not .Values.auth.existingSecret) (not .Values.auth.customPasswordFiles) }} - {{- true -}} -{{- end -}} -{{- end -}} - -{{/* -Returns the available value for certain key in an existing secret (if it exists), -otherwise it generates a random value. -*/}} -{{- define "getValueFromSecret" }} - {{- $len := (default 16 .Length) | int -}} - {{- $obj := (lookup "v1" "Secret" .Namespace .Name).data -}} - {{- if $obj }} - {{- index $obj .Key | b64dec -}} - {{- else -}} - {{- randAlphaNum $len -}} - {{- end -}} -{{- end }} - -{{/* Check if there are rolling tags in the images */}} -{{- define "mysql.checkRollingTags" -}} -{{- include "common.warnings.rollingTag" .Values.image }} -{{- include "common.warnings.rollingTag" .Values.metrics.image }} -{{- include "common.warnings.rollingTag" .Values.volumePermissions.image }} +{{ default (include "mysql.fullname" .) .Values.existingSecret }} {{- end -}} {{/* -Compile all warnings into a single message, and call fail. +Create the name of the service account to use */}} -{{- define "mysql.validateValues" -}} -{{- $messages := list -}} -{{- $messages := without $messages "" -}} -{{- $message := join "\n" $messages -}} - -{{- if $message -}} -{{- printf "\nVALUES VALIDATION:\n%s" $message | fail -}} +{{- define "mysql.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} +{{ default (include "mysql.fullname" .) .Values.serviceAccount.name }} +{{- else -}} +{{ default "default" .Values.serviceAccount.name }} {{- end -}} {{- end -}} diff --git a/deployment/charts/mysql/templates/configurationFiles-configmap.yaml b/deployment/charts/mysql/templates/configurationFiles-configmap.yaml new file mode 100644 index 0000000..ebed8cc --- /dev/null +++ b/deployment/charts/mysql/templates/configurationFiles-configmap.yaml @@ -0,0 +1,12 @@ +{{- if .Values.configurationFiles }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "mysql.fullname" . }}-configuration + namespace: {{ .Release.Namespace }} +data: +{{- range $key, $val := .Values.configurationFiles }} + {{ $key }}: |- +{{ $val | indent 4}} +{{- end }} +{{- end -}} \ No newline at end of file diff --git a/deployment/charts/mysql/templates/deployment.yaml b/deployment/charts/mysql/templates/deployment.yaml new file mode 100644 index 0000000..94f94b0 --- /dev/null +++ b/deployment/charts/mysql/templates/deployment.yaml @@ -0,0 +1,259 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "mysql.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mysql.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +{{- with .Values.deploymentAnnotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} + +spec: + strategy: +{{ toYaml .Values.strategy | indent 4 }} + selector: + matchLabels: + app: {{ template "mysql.fullname" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "mysql.fullname" . }} + release: {{ .Release.Name }} +{{- with .Values.podLabels }} +{{ toYaml . | indent 8 }} +{{- end }} +{{- with .Values.podAnnotations }} + annotations: +{{ toYaml . | indent 8 }} +{{- end }} + spec: + {{- if .Values.schedulerName }} + schedulerName: "{{ .Values.schedulerName }}" + {{- end }} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: +{{ toYaml .Values.imagePullSecrets | indent 8 }} + {{- end }} + {{- if .Values.priorityClassName }} + priorityClassName: "{{ .Values.priorityClassName }}" + {{- end }} + {{- if .Values.securityContext.enabled }} + securityContext: + fsGroup: {{ .Values.securityContext.fsGroup }} + runAsUser: {{ .Values.securityContext.runAsUser }} + {{- end }} + serviceAccountName: {{ template "mysql.serviceAccountName" . }} + initContainers: + - name: "remove-lost-found" + image: "{{ .Values.busybox.image}}:{{ .Values.busybox.tag }}" + imagePullPolicy: {{ .Values.imagePullPolicy | quote }} + resources: +{{ toYaml .Values.initContainer.resources | indent 10 }} + command: ["rm", "-fr", "/var/lib/mysql/lost+found"] + volumeMounts: + - name: data + mountPath: /var/lib/mysql + {{- if .Values.persistence.subPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if .Values.extraInitContainers }} +{{ tpl .Values.extraInitContainers . | indent 6 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} + containers: + - name: {{ template "mysql.fullname" . }} + image: "{{ .Values.image }}:{{ .Values.imageTag }}" + imagePullPolicy: {{ .Values.imagePullPolicy | quote }} + + {{- with .Values.args }} + args: + {{- range . }} + - {{ . | quote }} + {{- end }} + {{- end }} + resources: +{{ toYaml .Values.resources | indent 10 }} + env: + {{- if .Values.mysqlAllowEmptyPassword }} + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: "true" + {{- end }} + {{- if not (and .Values.allowEmptyRootPassword (not .Values.mysqlRootPassword)) }} + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mysql.secretName" . }} + key: mysql-root-password + {{- if .Values.mysqlAllowEmptyPassword }} + optional: true + {{- end }} + {{- end }} + {{- if not (and .Values.allowEmptyRootPassword (not .Values.mysqlPassword)) }} + - name: MYSQL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mysql.secretName" . }} + key: mysql-password + {{- if or .Values.mysqlAllowEmptyPassword (empty .Values.mysqlUser) }} + optional: true + {{- end }} + {{- end }} + - name: MYSQL_USER + value: {{ default "" .Values.mysqlUser | quote }} + - name: MYSQL_DATABASE + value: {{ default "" .Values.mysqlDatabase | quote }} + {{- if .Values.timezone }} + - name: TZ + value: {{ .Values.timezone }} + {{- end }} + {{- if .Values.extraEnvVars }} +{{ tpl .Values.extraEnvVars . | indent 8 }} + {{- end }} + ports: + - name: mysql + containerPort: 3306 + {{- if .Values.mysqlx.port.enabled }} + - name: mysqlx + port: 33060 + {{- end }} + livenessProbe: + exec: + command: + {{- if .Values.mysqlAllowEmptyPassword }} + - mysqladmin + - ping + {{- else }} + - sh + - -c + - "mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}" + {{- end }} + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + readinessProbe: + exec: + command: + {{- if .Values.mysqlAllowEmptyPassword }} + - mysqladmin + - ping + {{- else }} + - sh + - -c + - "mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}" + {{- end }} + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + volumeMounts: + - name: data + mountPath: /var/lib/mysql + {{- if .Values.persistence.subPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if .Values.configurationFiles }} + {{- range $key, $val := .Values.configurationFiles }} + - name: configurations + mountPath: {{ $.Values.configurationFilesPath }}{{ $key }} + subPath: {{ $key }} + {{- end -}} + {{- end }} + {{- if .Values.initializationFiles }} + - name: migrations + mountPath: /docker-entrypoint-initdb.d + {{- end }} + {{- if .Values.ssl.enabled }} + - name: certificates + mountPath: /ssl + {{- end }} + {{- if .Values.extraVolumeMounts }} +{{ tpl .Values.extraVolumeMounts . | indent 8 }} + {{- end }} + {{- if .Values.metrics.enabled }} + - name: metrics + image: "{{ .Values.metrics.image }}:{{ .Values.metrics.imageTag }}" + imagePullPolicy: {{ .Values.metrics.imagePullPolicy | quote }} + {{- if .Values.mysqlAllowEmptyPassword }} + command: + - 'sh' + - '-c' + - 'DATA_SOURCE_NAME="root@(localhost:3306)/" /bin/mysqld_exporter' + {{- else }} + env: + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mysql.secretName" . }} + key: mysql-root-password + command: + - 'sh' + - '-c' + - 'DATA_SOURCE_NAME="root:$MYSQL_ROOT_PASSWORD@(localhost:3306)/" /bin/mysqld_exporter' + {{- end }} + {{- range $f := .Values.metrics.flags }} + - {{ $f | quote }} + {{- end }} + ports: + - name: metrics + containerPort: 9104 + livenessProbe: + httpGet: + path: / + port: metrics + initialDelaySeconds: {{ .Values.metrics.livenessProbe.initialDelaySeconds }} + timeoutSeconds: {{ .Values.metrics.livenessProbe.timeoutSeconds }} + readinessProbe: + httpGet: + path: / + port: metrics + initialDelaySeconds: {{ .Values.metrics.readinessProbe.initialDelaySeconds }} + timeoutSeconds: {{ .Values.metrics.readinessProbe.timeoutSeconds }} + resources: +{{ toYaml .Values.metrics.resources | indent 10 }} + {{- end }} + volumes: + {{- if .Values.configurationFiles }} + - name: configurations + configMap: + name: {{ template "mysql.fullname" . }}-configuration + {{- end }} + {{- if .Values.initializationFiles }} + - name: migrations + configMap: + name: {{ template "mysql.fullname" . }}-initialization + {{- end }} + {{- if .Values.ssl.enabled }} + - name: certificates + secret: + secretName: {{ .Values.ssl.secret }} + {{- end }} + - name: data + {{- if .Values.persistence.enabled }} + persistentVolumeClaim: + claimName: {{ .Values.persistence.existingClaim | default (include "mysql.fullname" .) }} + {{- else }} + emptyDir: {} + {{- end -}} + {{- if .Values.extraVolumes }} +{{ tpl .Values.extraVolumes . | indent 6 }} + {{- end }} diff --git a/deployment/charts/mysql/templates/extra-list.yaml b/deployment/charts/mysql/templates/extra-list.yaml deleted file mode 100644 index 9ac65f9..0000000 --- a/deployment/charts/mysql/templates/extra-list.yaml +++ /dev/null @@ -1,4 +0,0 @@ -{{- range .Values.extraDeploy }} ---- -{{ include "common.tplvalues.render" (dict "value" . "context" $) }} -{{- end }} diff --git a/deployment/charts/mysql/templates/initializationFiles-configmap.yaml b/deployment/charts/mysql/templates/initializationFiles-configmap.yaml new file mode 100644 index 0000000..38c3795 --- /dev/null +++ b/deployment/charts/mysql/templates/initializationFiles-configmap.yaml @@ -0,0 +1,12 @@ +{{- if .Values.initializationFiles }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "mysql.fullname" . }}-initialization + namespace: {{ .Release.Namespace }} +data: +{{- range $key, $val := .Values.initializationFiles }} + {{ $key }}: |- +{{ $val | indent 4}} +{{- end }} +{{- end -}} \ No newline at end of file diff --git a/deployment/charts/mysql/templates/metrics-svc.yaml b/deployment/charts/mysql/templates/metrics-svc.yaml deleted file mode 100644 index 4d3339b..0000000 --- a/deployment/charts/mysql/templates/metrics-svc.yaml +++ /dev/null @@ -1,29 +0,0 @@ -{{- if .Values.metrics.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: {{ printf "%s-metrics" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" . | nindent 4 }} - {{- if .Values.commonLabels }} - {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- end }} - app.kubernetes.io/component: metrics - {{- if or .Values.metrics.service.annotations .Values.commonAnnotations }} - annotations: - {{- if .Values.metrics.service.annotations }} - {{- include "common.tplvalues.render" (dict "value" .Values.metrics.service.annotations "context" $) | nindent 4 }} - {{- end }} - {{- if .Values.commonAnnotations }} - {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} - {{- end }} -spec: - type: {{ .Values.metrics.service.type }} - ports: - - port: {{ .Values.metrics.service.port }} - targetPort: metrics - protocol: TCP - name: metrics - selector: {{- include "common.labels.matchLabels" $ | nindent 4 }} -{{- end }} diff --git a/deployment/charts/mysql/templates/networkpolicy.yaml b/deployment/charts/mysql/templates/networkpolicy.yaml deleted file mode 100644 index 6b62bb5..0000000 --- a/deployment/charts/mysql/templates/networkpolicy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -{{- if .Values.networkPolicy.enabled }} -kind: NetworkPolicy -apiVersion: {{ template "common.capabilities.networkPolicy.apiVersion" . }} -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ include "common.names.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.matchLabels" . | nindent 6 }} - ingress: - # Allow inbound connections - - ports: - - port: {{ .Values.primary.service.ports.mysql }} - {{- if not .Values.networkPolicy.allowExternal }} - from: - - podSelector: - matchLabels: - {{ template "common.names.fullname" . }}-client: "true" - {{- if .Values.networkPolicy.explicitNamespacesSelector }} - namespaceSelector: -{{ toYaml .Values.networkPolicy.explicitNamespacesSelector | indent 12 }} - {{- end }} - - podSelector: - matchLabels: - {{- include "common.labels.matchLabels" . | nindent 14 }} - {{- end }} - {{- if .Values.metrics.enabled }} - # Allow prometheus scrapes - - ports: - - port: 9104 - {{- end }} -{{- end }} diff --git a/deployment/charts/mysql/templates/primary/configmap.yaml b/deployment/charts/mysql/templates/primary/configmap.yaml deleted file mode 100644 index 82d0774..0000000 --- a/deployment/charts/mysql/templates/primary/configmap.yaml +++ /dev/null @@ -1,18 +0,0 @@ -{{- if (include "mysql.primary.createConfigmap" .) }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "mysql.primary.fullname" . }} - namespace: {{ include "common.names.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: |- - {{- include "common.tplvalues.render" ( dict "value" .Values.primary.configuration "context" $ ) | nindent 4 }} -{{- end -}} diff --git a/deployment/charts/mysql/templates/primary/initialization-configmap.yaml b/deployment/charts/mysql/templates/primary/initialization-configmap.yaml deleted file mode 100644 index a34f80d..0000000 --- a/deployment/charts/mysql/templates/primary/initialization-configmap.yaml +++ /dev/null @@ -1,17 +0,0 @@ -{{- if and .Values.initdbScripts (not .Values.initdbScriptsConfigMap) }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ printf "%s-init-scripts" (include "mysql.primary.fullname" .) }} - namespace: {{ include "common.names.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: -{{- include "common.tplvalues.render" (dict "value" .Values.initdbScripts "context" .) | nindent 2 }} -{{- end }} diff --git a/deployment/charts/mysql/templates/primary/pdb.yaml b/deployment/charts/mysql/templates/primary/pdb.yaml deleted file mode 100644 index ca22a0e..0000000 --- a/deployment/charts/mysql/templates/primary/pdb.yaml +++ /dev/null @@ -1,25 +0,0 @@ -{{- if .Values.primary.pdb.create }} -apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} -kind: PodDisruptionBudget -metadata: - name: {{ include "mysql.primary.fullname" . }} - namespace: {{ include "common.names.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/deployment/charts/mysql/templates/primary/statefulset.yaml b/deployment/charts/mysql/templates/primary/statefulset.yaml deleted file mode 100644 index 7be0254..0000000 --- a/deployment/charts/mysql/templates/primary/statefulset.yaml +++ /dev/null @@ -1,382 +0,0 @@ -apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} -kind: StatefulSet -metadata: - name: {{ include "mysql.primary.fullname" . }} - namespace: {{ include "common.names.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 - podManagementPolicy: {{ .Values.primary.podManagementPolicy | quote }} - selector: - matchLabels: {{ include "common.labels.matchLabels" . | nindent 6 }} - app.kubernetes.io/component: primary - serviceName: {{ include "mysql.primary.fullname" . }} - {{- if .Values.primary.updateStrategy }} - updateStrategy: {{- toYaml .Values.primary.updateStrategy | nindent 4 }} - {{- end }} - template: - metadata: - annotations: - {{- if (include "mysql.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 }} - spec: - serviceAccountName: {{ template "mysql.serviceAccountName" . }} - {{- include "mysql.imagePullSecrets" . | nindent 6 }} - {{- if .Values.primary.hostAliases }} - hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.primary.hostAliases "context" $) | nindent 8 }} - {{- end }} - {{- 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 "context" $) | nindent 10 }} - podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.primary.podAntiAffinityPreset "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.priorityClassName }} - priorityClassName: {{ .Values.primary.priorityClassName | quote }} - {{- end }} - {{- if .Values.primary.runtimeClassName }} - runtimeClassName: {{ .Values.primary.runtimeClassName | quote }} - {{- end }} - {{- if .Values.primary.schedulerName }} - schedulerName: {{ .Values.primary.schedulerName | quote }} - {{- end }} - {{- if .Values.primary.topologySpreadConstraints }} - topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.primary.topologySpreadConstraints "context" .) | nindent 8 }} - {{- end }} - {{- if .Values.primary.podSecurityContext.enabled }} - securityContext: {{- omit .Values.primary.podSecurityContext "enabled" | toYaml | nindent 8 }} - {{- end }} - {{- if .Values.primary.terminationGracePeriodSeconds }} - terminationGracePeriodSeconds: {{ .Values.primary.terminationGracePeriodSeconds }} - {{- end }} - initContainers: - {{- if and .Values.primary.podSecurityContext.enabled .Values.volumePermissions.enabled .Values.primary.persistence.enabled }} - - name: volume-permissions - image: {{ include "mysql.volumePermissions.image" . }} - imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} - command: - - /bin/bash - - -ec - - | - mkdir -p "/bitnami/mysql" - chown "{{ .Values.primary.containerSecurityContext.runAsUser }}:{{ .Values.primary.podSecurityContext.fsGroup }}" "/bitnami/mysql" - find "/bitnami/mysql" -mindepth 1 -maxdepth 1 -not -name ".snapshot" -not -name "lost+found" | xargs -r chown -R "{{ .Values.primary.containerSecurityContext.runAsUser }}:{{ .Values.primary.podSecurityContext.fsGroup }}" - securityContext: - runAsUser: 0 - {{- if .Values.volumePermissions.resources }} - resources: {{- toYaml .Values.volumePermissions.resources | nindent 12 }} - {{- end }} - volumeMounts: - - name: data - mountPath: /bitnami/mysql - {{- if .Values.primary.persistence.subPath }} - subPath: {{ .Values.primary.persistence.subPath }} - {{- end }} - {{- end }} - {{- if .Values.primary.initContainers }} - {{- include "common.tplvalues.render" (dict "value" .Values.primary.initContainers "context" $) | nindent 8 }} - {{- end }} - containers: - - name: mysql - image: {{ include "mysql.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: MYSQL_ROOT_PASSWORD_FILE - value: {{ default "/opt/bitnami/mysql/secrets/mysql-root-password" .Values.auth.customPasswordFiles.root }} - {{- else }} - - name: MYSQL_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "mysql.secretName" . }} - key: mysql-root-password - {{- end }} - {{- if not (empty .Values.auth.username) }} - - name: MYSQL_USER - value: {{ .Values.auth.username | quote }} - {{- if .Values.auth.usePasswordFiles }} - - name: MYSQL_PASSWORD_FILE - value: {{ default "/opt/bitnami/mysql/secrets/mysql-password" .Values.auth.customPasswordFiles.user }} - {{- else }} - - name: MYSQL_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "mysql.secretName" . }} - key: mysql-password - {{- end }} - {{- end }} - {{- if and .Values.auth.createDatabase .Values.auth.database }} - - name: MYSQL_DATABASE - value: {{ .Values.auth.database | quote }} - {{- end }} - {{- if eq .Values.architecture "replication" }} - - name: MYSQL_REPLICATION_MODE - value: "master" - - name: MYSQL_REPLICATION_USER - value: {{ .Values.auth.replicationUser | quote }} - {{- if .Values.auth.usePasswordFiles }} - - name: MYSQL_REPLICATION_PASSWORD_FILE - value: {{ default "/opt/bitnami/mysql/secrets/mysql-replication-password" .Values.auth.customPasswordFiles.replicator }} - {{- else }} - - name: MYSQL_REPLICATION_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "mysql.secretName" . }} - key: mysql-replication-password - {{- end }} - {{- end }} - {{- if .Values.primary.extraFlags }} - - name: MYSQL_EXTRA_FLAGS - value: "{{ .Values.primary.extraFlags }}" - {{- end }} - {{- if .Values.primary.extraEnvVars }} - {{- include "common.tplvalues.render" (dict "value" .Values.primary.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - envFrom: - {{- if .Values.primary.extraEnvVarsCM }} - - configMapRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.primary.extraEnvVarsCM "context" $) }} - {{- end }} - {{- if .Values.primary.extraEnvVarsSecret }} - - secretRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.primary.extraEnvVarsSecret "context" $) }} - {{- end }} - ports: - - name: mysql - containerPort: 3306 - {{- if not .Values.diagnosticMode.enabled }} - {{- if .Values.primary.customLivenessProbe }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.primary.customLivenessProbe "context" $) | nindent 12 }} - {{- else if .Values.primary.livenessProbe.enabled }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.primary.livenessProbe "enabled") "context" $) | nindent 12 }} - exec: - command: - - /bin/bash - - -ec - - | - password_aux="${MYSQL_ROOT_PASSWORD:-}" - if [[ -f "${MYSQL_ROOT_PASSWORD_FILE:-}" ]]; then - password_aux=$(cat "$MYSQL_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: {{- include "common.tplvalues.render" (dict "value" (omit .Values.primary.readinessProbe "enabled") "context" $) | nindent 12 }} - exec: - command: - - /bin/bash - - -ec - - | - password_aux="${MYSQL_ROOT_PASSWORD:-}" - if [[ -f "${MYSQL_ROOT_PASSWORD_FILE:-}" ]]; then - password_aux=$(cat "$MYSQL_ROOT_PASSWORD_FILE") - fi - mysqladmin status -uroot -p"${password_aux}" - {{- end }} - {{- if .Values.primary.customStartupProbe }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.primary.customStartupProbe "context" $) | nindent 12 }} - {{- else if .Values.primary.startupProbe.enabled }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.primary.startupProbe "enabled") "context" $) | nindent 12 }} - exec: - command: - - /bin/bash - - -ec - - | - password_aux="${MYSQL_ROOT_PASSWORD:-}" - if [[ -f "${MYSQL_ROOT_PASSWORD_FILE:-}" ]]; then - password_aux=$(cat "$MYSQL_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/mysql - {{- 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/mysql/conf/my.cnf - subPath: my.cnf - {{- end }} - {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} - - name: mysql-credentials - mountPath: /opt/bitnami/mysql/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 "mysql.metrics.image" . }} - imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} - env: - {{- if .Values.auth.usePasswordFiles }} - - name: MYSQL_ROOT_PASSWORD_FILE - value: {{ default "/opt/bitnami/mysqld-exporter/secrets/mysql-root-password" .Values.auth.customPasswordFiles.root }} - {{- else }} - - name: MYSQL_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: {{ include "mysql.secretName" . }} - key: mysql-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="${MYSQL_ROOT_PASSWORD:-}" - if [[ -f "${MYSQL_ROOT_PASSWORD_FILE:-}" ]]; then - password_aux=$(cat "$MYSQL_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 }} - {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} - volumeMounts: - - name: mysql-credentials - mountPath: /opt/bitnami/mysqld-exporter/secrets/ - {{- 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 "mysql.primary.configmapName" . }} - {{- end }} - {{- if or .Values.initdbScriptsConfigMap .Values.initdbScripts }} - - name: custom-init-scripts - configMap: - name: {{ include "mysql.initdbScriptsCM" . }} - {{- end }} - {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} - - name: mysql-credentials - secret: - secretName: {{ include "mysql.secretName" . }} - items: - - key: mysql-root-password - path: mysql-root-password - - key: mysql-password - path: mysql-password - {{- if eq .Values.architecture "replication" }} - - key: mysql-replication-password - path: mysql-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.commonLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 10 }} - {{- end }} - annotations: - {{- if .Values.primary.persistence.annotations }} - {{- include "common.tplvalues.render" (dict "value" .Values.primary.persistence.annotations "context" $) | nindent 10 }} - {{- end }} - {{- if .Values.commonAnnotations }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonAnnotations "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) | nindent 8 }} - {{- if .Values.primary.persistence.selector }} - selector: {{- include "common.tplvalues.render" (dict "value" .Values.primary.persistence.selector "context" $) | nindent 10 }} - {{- end -}} - {{- end }} diff --git a/deployment/charts/mysql/templates/primary/svc-headless.yaml b/deployment/charts/mysql/templates/primary/svc-headless.yaml deleted file mode 100644 index c430d94..0000000 --- a/deployment/charts/mysql/templates/primary/svc-headless.yaml +++ /dev/null @@ -1,29 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ include "mysql.primary.fullname" . }}-headless - namespace: {{ include "common.names.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 or .Values.primary.service.headless.annotations .Values.commonAnnotations }} - annotations: - {{- if .Values.primary.service.headless.annotations }} - {{- include "common.tplvalues.render" (dict "value" .Values.primary.service.headless.annotations "context" $) | nindent 4 }} - {{- end }} - {{- if .Values.commonAnnotations }} - {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} - {{- end }} -spec: - type: ClusterIP - clusterIP: None - publishNotReadyAddresses: true - ports: - - name: mysql - port: {{ .Values.primary.service.ports.mysql }} - targetPort: mysql - selector: {{ include "common.labels.matchLabels" . | nindent 4 }} - app.kubernetes.io/component: primary diff --git a/deployment/charts/mysql/templates/primary/svc.yaml b/deployment/charts/mysql/templates/primary/svc.yaml deleted file mode 100644 index b61d453..0000000 --- a/deployment/charts/mysql/templates/primary/svc.yaml +++ /dev/null @@ -1,52 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ include "mysql.primary.fullname" . }} - namespace: {{ include "common.names.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 }} -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 .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 }} - {{- if 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") (not (empty .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 }} - ports: - - name: mysql - port: {{ .Values.primary.service.ports.mysql }} - protocol: TCP - targetPort: mysql - {{- if (and (or (eq .Values.primary.service.type "NodePort") (eq .Values.primary.service.type "LoadBalancer")) .Values.primary.service.nodePorts.mysql) }} - nodePort: {{ .Values.primary.service.nodePorts.mysql }} - {{- else if eq .Values.primary.service.type "ClusterIP" }} - nodePort: null - {{- 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/deployment/charts/mysql/templates/prometheusrule.yaml b/deployment/charts/mysql/templates/prometheusrule.yaml deleted file mode 100644 index 64fa44f..0000000 --- a/deployment/charts/mysql/templates/prometheusrule.yaml +++ /dev/null @@ -1,22 +0,0 @@ -{{- if and .Values.metrics.enabled .Values.metrics.prometheusRule.enabled }} -apiVersion: monitoring.coreos.com/v1 -kind: PrometheusRule -metadata: - name: {{ include "common.names.fullname" . }} - namespace: {{ default .Release.Namespace .Values.metrics.prometheusRule.namespace }} - 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/deployment/charts/mysql/templates/pvc.yaml b/deployment/charts/mysql/templates/pvc.yaml new file mode 100644 index 0000000..39e9bf8 --- /dev/null +++ b/deployment/charts/mysql/templates/pvc.yaml @@ -0,0 +1,29 @@ +{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ template "mysql.fullname" . }} + namespace: {{ .Release.Namespace }} +{{- with .Values.persistence.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} + labels: + app: {{ template "mysql.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + accessModes: + - {{ .Values.persistence.accessMode | quote }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} +{{- if .Values.persistence.storageClass }} +{{- if (eq "-" .Values.persistence.storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: "{{ .Values.persistence.storageClass }}" +{{- end }} +{{- end }} +{{- end }} diff --git a/deployment/charts/mysql/templates/role.yaml b/deployment/charts/mysql/templates/role.yaml deleted file mode 100644 index 1ccc00a..0000000 --- a/deployment/charts/mysql/templates/role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -{{- if and .Values.serviceAccount.create .Values.rbac.create }} -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: Role -metadata: - name: {{ include "common.names.fullname" . }} - namespace: {{ include "common.names.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 - {{- if .Values.rbac.rules }} - {{- include "common.tplvalues.render" ( dict "value" .Values.rbac.rules "context" $ ) | nindent 2 }} - {{- end }} -{{- end }} diff --git a/deployment/charts/mysql/templates/rolebinding.yaml b/deployment/charts/mysql/templates/rolebinding.yaml deleted file mode 100644 index 9b05208..0000000 --- a/deployment/charts/mysql/templates/rolebinding.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- if and .Values.serviceAccount.create .Values.rbac.create }} -kind: RoleBinding -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -metadata: - name: {{ include "common.names.fullname" . }} - namespace: {{ include "common.names.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 "mysql.serviceAccountName" . }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: {{ include "common.names.fullname" . -}} -{{- end }} diff --git a/deployment/charts/mysql/templates/secondary/configmap.yaml b/deployment/charts/mysql/templates/secondary/configmap.yaml deleted file mode 100644 index c94724f..0000000 --- a/deployment/charts/mysql/templates/secondary/configmap.yaml +++ /dev/null @@ -1,18 +0,0 @@ -{{- if (include "mysql.secondary.createConfigmap" .) }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "mysql.secondary.fullname" . }} - namespace: {{ include "common.names.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: |- - {{- include "common.tplvalues.render" ( dict "value" .Values.secondary.configuration "context" $ ) | nindent 4 }} -{{- end -}} diff --git a/deployment/charts/mysql/templates/secondary/pdb.yaml b/deployment/charts/mysql/templates/secondary/pdb.yaml deleted file mode 100644 index b4a5aee..0000000 --- a/deployment/charts/mysql/templates/secondary/pdb.yaml +++ /dev/null @@ -1,25 +0,0 @@ -{{- if and (eq .Values.architecture "replication") .Values.secondary.pdb.create }} -apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} -kind: PodDisruptionBudget -metadata: - name: {{ include "mysql.secondary.fullname" . }} - namespace: {{ include "common.names.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/deployment/charts/mysql/templates/secondary/statefulset.yaml b/deployment/charts/mysql/templates/secondary/statefulset.yaml deleted file mode 100644 index 3b731b5..0000000 --- a/deployment/charts/mysql/templates/secondary/statefulset.yaml +++ /dev/null @@ -1,363 +0,0 @@ -{{- if eq .Values.architecture "replication" }} -apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} -kind: StatefulSet -metadata: - name: {{ include "mysql.secondary.fullname" . }} - namespace: {{ include "common.names.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 }} - podManagementPolicy: {{ .Values.secondary.podManagementPolicy | quote }} - selector: - matchLabels: {{ include "common.labels.matchLabels" . | nindent 6 }} - app.kubernetes.io/component: secondary - serviceName: {{ include "mysql.secondary.fullname" . }} - {{- if .Values.secondary.updateStrategy }} - updateStrategy: {{- toYaml .Values.secondary.updateStrategy | nindent 4 }} - {{- end }} - template: - metadata: - annotations: - {{- if (include "mysql.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 }} - spec: - serviceAccountName: {{ include "mysql.serviceAccountName" . }} - {{- include "mysql.imagePullSecrets" . | nindent 6 }} - {{- 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 "context" $) | nindent 10 }} - podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.secondary.podAntiAffinityPreset "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.priorityClassName }} - priorityClassName: {{ .Values.secondary.priorityClassName | quote }} - {{- end }} - {{- if .Values.secondary.runtimeClassName }} - runtimeClassName: {{ .Values.secondary.runtimeClassName | quote }} - {{- end }} - {{- if .Values.secondary.schedulerName }} - schedulerName: {{ .Values.secondary.schedulerName | quote }} - {{- end }} - {{- if .Values.secondary.topologySpreadConstraints }} - topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.topologySpreadConstraints "context" .) | nindent 8 }} - {{- end }} - {{- if .Values.secondary.podSecurityContext.enabled }} - securityContext: {{- omit .Values.secondary.podSecurityContext "enabled" | toYaml | nindent 8 }} - {{- end }} - {{- if .Values.secondary.terminationGracePeriodSeconds }} - terminationGracePeriodSeconds: {{ .Values.secondary.terminationGracePeriodSeconds }} - {{- end }} - initContainers: - {{- if and .Values.secondary.podSecurityContext.enabled .Values.volumePermissions.enabled .Values.secondary.persistence.enabled }} - - name: volume-permissions - image: {{ include "mysql.volumePermissions.image" . }} - imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} - command: - - /bin/bash - - -ec - - | - mkdir -p "/bitnami/mysql" - chown "{{ .Values.secondary.containerSecurityContext.runAsUser }}:{{ .Values.secondary.podSecurityContext.fsGroup }}" "/bitnami/mysql" - find "/bitnami/mysql" -mindepth 1 -maxdepth 1 -not -name ".snapshot" -not -name "lost+found" | xargs -r chown -R "{{ .Values.secondary.containerSecurityContext.runAsUser }}:{{ .Values.secondary.podSecurityContext.fsGroup }}" - securityContext: - runAsUser: 0 - {{- if .Values.volumePermissions.resources }} - resources: {{- toYaml .Values.volumePermissions.resources | nindent 12 }} - {{- end }} - volumeMounts: - - name: data - mountPath: /bitnami/mysql - {{- if .Values.secondary.persistence.subPath }} - subPath: {{ .Values.secondary.persistence.subPath }} - {{- end }} - {{- end }} - {{- if .Values.secondary.initContainers }} - {{- include "common.tplvalues.render" (dict "value" .Values.secondary.initContainers "context" $) | nindent 8 }} - {{- end }} - containers: - - name: mysql - image: {{ include "mysql.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: MYSQL_REPLICATION_MODE - value: "slave" - - name: MYSQL_MASTER_HOST - value: {{ include "mysql.primary.fullname" . }} - - name: MYSQL_MASTER_PORT_NUMBER - value: {{ .Values.primary.service.ports.mysql | quote }} - - name: MYSQL_MASTER_ROOT_USER - value: "root" - - name: MYSQL_REPLICATION_USER - value: {{ .Values.auth.replicationUser | quote }} - {{- if .Values.auth.usePasswordFiles }} - - name: MYSQL_MASTER_ROOT_PASSWORD_FILE - value: {{ default "/opt/bitnami/mysql/secrets/mysql-root-password" .Values.auth.customPasswordFiles.root }} - - name: MYSQL_REPLICATION_PASSWORD_FILE - value: {{ default "/opt/bitnami/mysql/secrets/mysql-replication-password" .Values.auth.customPasswordFiles.replicator }} - {{- else }} - - name: MYSQL_MASTER_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "mysql.secretName" . }} - key: mysql-root-password - - name: MYSQL_REPLICATION_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "mysql.secretName" . }} - key: mysql-replication-password - {{- end }} - {{- if .Values.secondary.extraFlags }} - - name: MYSQL_EXTRA_FLAGS - value: "{{ .Values.secondary.extraFlags }}" - {{- end }} - {{- if .Values.secondary.extraEnvVars }} - {{- include "common.tplvalues.render" (dict "value" .Values.secondary.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - envFrom: - {{- if .Values.secondary.extraEnvVarsCM }} - - configMapRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.secondary.extraEnvVarsCM "context" $) }} - {{- end }} - {{- if .Values.secondary.extraEnvVarsSecret }} - - secretRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.secondary.extraEnvVarsSecret "context" $) }} - {{- end }} - ports: - - name: mysql - containerPort: 3306 - {{- if not .Values.diagnosticMode.enabled }} - {{- if .Values.secondary.customLivenessProbe }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.customLivenessProbe "context" $) | nindent 12 }} - {{- else if .Values.secondary.livenessProbe.enabled }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.secondary.livenessProbe "enabled") "context" $) | nindent 12 }} - exec: - command: - - /bin/bash - - -ec - - | - password_aux="${MYSQL_MASTER_ROOT_PASSWORD:-}" - if [[ -f "${MYSQL_MASTER_ROOT_PASSWORD_FILE:-}" ]]; then - password_aux=$(cat "$MYSQL_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: {{- include "common.tplvalues.render" (dict "value" (omit .Values.secondary.readinessProbe "enabled") "context" $) | nindent 12 }} - exec: - command: - - /bin/bash - - -ec - - | - password_aux="${MYSQL_MASTER_ROOT_PASSWORD:-}" - if [[ -f "${MYSQL_MASTER_ROOT_PASSWORD_FILE:-}" ]]; then - password_aux=$(cat "$MYSQL_MASTER_ROOT_PASSWORD_FILE") - fi - mysqladmin status -uroot -p"${password_aux}" - {{- end }} - {{- if .Values.secondary.customStartupProbe }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.secondary.customStartupProbe "context" $) | nindent 12 }} - {{- else if .Values.secondary.startupProbe.enabled }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.secondary.startupProbe "enabled") "context" $) | nindent 12 }} - exec: - command: - - /bin/bash - - -ec - - | - password_aux="${MYSQL_MASTER_ROOT_PASSWORD:-}" - if [[ -f "${MYSQL_MASTER_ROOT_PASSWORD_FILE:-}" ]]; then - password_aux=$(cat "$MYSQL_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/mysql - {{- if .Values.secondary.persistence.subPath }} - subPath: {{ .Values.secondary.persistence.subPath }} - {{- end }} - {{- if or .Values.initdbScriptsConfigMap .Values.initdbScripts }} - - name: custom-init-scripts - mountPath: /docker-entrypoint-initdb.d - {{- end }} - {{- if or .Values.secondary.configuration .Values.secondary.existingConfigmap }} - - name: config - mountPath: /opt/bitnami/mysql/conf/my.cnf - subPath: my.cnf - {{- end }} - {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} - - name: mysql-credentials - mountPath: /opt/bitnami/mysql/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 "mysql.metrics.image" . }} - imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} - env: - {{- if .Values.auth.usePasswordFiles }} - - name: MYSQL_ROOT_PASSWORD_FILE - value: {{ default "/opt/bitnami/mysqld-exporter/secrets/mysql-root-password" .Values.auth.customPasswordFiles.root }} - {{- else }} - - name: MYSQL_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "mysql.secretName" . }} - key: mysql-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="${MYSQL_ROOT_PASSWORD:-}" - if [[ -f "${MYSQL_ROOT_PASSWORD_FILE:-}" ]]; then - password_aux=$(cat "$MYSQL_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 }} - {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} - volumeMounts: - - name: mysql-credentials - mountPath: /opt/bitnami/mysqld-exporter/secrets/ - {{- end }} - {{- end }} - {{- if .Values.secondary.sidecars }} - {{- include "common.tplvalues.render" (dict "value" .Values.secondary.sidecars "context" $) | nindent 8 }} - {{- end }} - volumes: - {{- if or .Values.initdbScriptsConfigMap .Values.initdbScripts }} - - name: custom-init-scripts - configMap: - name: {{ include "mysql.initdbScriptsCM" . }} - {{- end }} - {{- if or .Values.secondary.configuration .Values.secondary.existingConfigmap }} - - name: config - configMap: - name: {{ include "mysql.secondary.configmapName" . }} - {{- end }} - {{- if and .Values.auth.usePasswordFiles (not .Values.auth.customPasswordFiles) }} - - name: mysql-credentials - secret: - secretName: {{ template "mysql.secretName" . }} - items: - - key: mysql-root-password - path: mysql-root-password - - key: mysql-replication-password - path: mysql-replication-password - {{- end }} - {{- if .Values.secondary.extraVolumes }} - {{- include "common.tplvalues.render" (dict "value" .Values.secondary.extraVolumes "context" $) | nindent 8 }} - {{- end }} - {{- if and .Values.secondary.persistence.enabled .Values.secondary.persistence.existingClaim }} - - name: data - persistentVolumeClaim: - claimName: {{ tpl .Values.secondary.persistence.existingClaim . }} - {{- else 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.commonLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 10 }} - {{- end }} - annotations: - {{- if .Values.secondary.persistence.annotations }} - {{- include "common.tplvalues.render" (dict "value" .Values.secondary.persistence.annotations "context" $) | nindent 10 }} - {{- end }} - {{- if .Values.commonAnnotations }} - {{- include "common.tplvalues.render" (dict "value" .Values.commonAnnotations "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) | nindent 8 }} - {{- 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/deployment/charts/mysql/templates/secondary/svc-headless.yaml b/deployment/charts/mysql/templates/secondary/svc-headless.yaml deleted file mode 100644 index 44cfa4a..0000000 --- a/deployment/charts/mysql/templates/secondary/svc-headless.yaml +++ /dev/null @@ -1,31 +0,0 @@ -{{- if eq .Values.architecture "replication" }} -apiVersion: v1 -kind: Service -metadata: - name: {{ include "mysql.secondary.fullname" . }}-headless - namespace: {{ include "common.names.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 or .Values.secondary.service.headless.annotations .Values.commonAnnotations }} - annotations: - {{- if .Values.secondary.service.headless.annotations }} - {{- include "common.tplvalues.render" (dict "value" .Values.secondary.service.headless.annotations "context" $) | nindent 4 }} - {{- end }} - {{- if .Values.commonAnnotations }} - {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} - {{- end }} -spec: - type: ClusterIP - clusterIP: None - publishNotReadyAddresses: true - ports: - - name: mysql - port: {{ .Values.secondary.service.ports.mysql }} - targetPort: mysql - selector: {{ include "common.labels.matchLabels" . | nindent 4 }} - app.kubernetes.io/component: secondary -{{- end }} diff --git a/deployment/charts/mysql/templates/secondary/svc.yaml b/deployment/charts/mysql/templates/secondary/svc.yaml deleted file mode 100644 index e6e662c..0000000 --- a/deployment/charts/mysql/templates/secondary/svc.yaml +++ /dev/null @@ -1,54 +0,0 @@ -{{- if eq .Values.architecture "replication" }} -apiVersion: v1 -kind: Service -metadata: - name: {{ include "mysql.secondary.fullname" . }} - namespace: {{ include "common.names.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 }} -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 .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 }} - {{- if 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") (not (empty .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 }} - ports: - - name: mysql - port: {{ .Values.secondary.service.ports.mysql }} - protocol: TCP - targetPort: mysql - {{- if (and (or (eq .Values.secondary.service.type "NodePort") (eq .Values.secondary.service.type "LoadBalancer")) .Values.secondary.service.nodePorts.mysql) }} - nodePort: {{ .Values.secondary.service.nodePorts.mysql }} - {{- else if eq .Values.secondary.service.type "ClusterIP" }} - nodePort: null - {{- 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/deployment/charts/mysql/templates/secrets.yaml b/deployment/charts/mysql/templates/secrets.yaml old mode 100644 new mode 100755 index 6da5327..d9dfd12 --- a/deployment/charts/mysql/templates/secrets.yaml +++ b/deployment/charts/mysql/templates/secrets.yaml @@ -1,21 +1,51 @@ -{{- if eq (include "mysql.createSecret" .) "true" }} +{{- if not .Values.existingSecret }} +{{- if or (not .Values.allowEmptyRootPassword) (or .Values.mysqlRootPassword .Values.mysqlPassword) }} apiVersion: v1 kind: Secret metadata: - name: {{ include "common.names.fullname" . }} - namespace: {{ include "common.names.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 }} + name: {{ template "mysql.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mysql.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" type: Opaque data: - mysql-root-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "mysql-root-password" "length" 10 "providedValues" (list "auth.rootPassword") "context" $) }} - mysql-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "mysql-password" "length" 10 "providedValues" (list "auth.password") "context" $) }} - {{- if eq .Values.architecture "replication" }} - mysql-replication-password: {{ include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "mysql-replication-password" "length" 10 "providedValues" (list "auth.replicationPassword") "context" $) }} - {{- end }} + {{ if .Values.mysqlRootPassword }} + mysql-root-password: {{ .Values.mysqlRootPassword | b64enc | quote }} + {{ else }} + {{ if not .Values.allowEmptyRootPassword }} + mysql-root-password: {{ randAlphaNum 10 | b64enc | quote }} + {{ end }} + {{ end }} + {{ if .Values.mysqlPassword }} + mysql-password: {{ .Values.mysqlPassword | b64enc | quote }} + {{ else }} + {{ if not .Values.allowEmptyRootPassword }} + mysql-password: {{ randAlphaNum 10 | b64enc | quote }} + {{ end }} + {{ end }} +{{ end }} +{{- if .Values.ssl.enabled }} +{{ if .Values.ssl.certificates }} +{{- range .Values.ssl.certificates }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ .name }} + labels: + app: {{ template "mysql.fullname" $ }} + chart: "{{ $.Chart.Name }}-{{ $.Chart.Version }}" + release: "{{ $.Release.Name }}" + heritage: "{{ $.Release.Service }}" +type: Opaque +data: + ca.pem: {{ .ca | b64enc }} + server-cert.pem: {{ .cert | b64enc }} + server-key.pem: {{ .key | b64enc }} +{{- end }} +{{- end }} +{{- end }} {{- end }} diff --git a/deployment/charts/mysql/templates/serviceaccount.yaml b/deployment/charts/mysql/templates/serviceaccount.yaml index 5044961..36ce6b3 100644 --- a/deployment/charts/mysql/templates/serviceaccount.yaml +++ b/deployment/charts/mysql/templates/serviceaccount.yaml @@ -2,22 +2,10 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: {{ include "mysql.serviceAccountName" . }} - namespace: {{ include "common.names.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.commonAnnotations }} - {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} - {{- if .Values.serviceAccount.annotations }} - {{- include "common.tplvalues.render" ( dict "value" .Values.serviceAccount.annotations "context" $ ) | nindent 4 }} - {{- end }} -automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} -{{- if (not .Values.auth.customPasswordFiles) }} -secrets: - - name: {{ template "mysql.secretName" . }} -{{- end }} + name: {{ template "mysql.serviceAccountName" . }} + labels: + app: {{ template "mysql.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" {{- end }} diff --git a/deployment/charts/mysql/templates/servicemonitor.yaml b/deployment/charts/mysql/templates/servicemonitor.yaml index 47a9dad..bd830be 100644 --- a/deployment/charts/mysql/templates/servicemonitor.yaml +++ b/deployment/charts/mysql/templates/servicemonitor.yaml @@ -2,48 +2,25 @@ apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: - name: {{ include "common.names.fullname" . }} - namespace: {{ default (include "common.names.namespace" .) .Values.metrics.serviceMonitor.namespace }} - labels: {{- include "common.labels.standard" . | nindent 4 }} - {{- if .Values.metrics.serviceMonitor.labels }} - {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.labels "context" $ ) | nindent 4 }} - {{- end }} - {{- 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.metrics.serviceMonitor.annotations }} - {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.serviceMonitor.annotations "context" $ ) | nindent 4 }} + name: {{ include "mysql.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mysql.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" + {{- if .Values.metrics.serviceMonitor.additionalLabels }} +{{ toYaml .Values.metrics.serviceMonitor.additionalLabels | indent 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 }} + interval: 30s namespaceSelector: matchNames: - - {{ include "common.names.namespace" . | quote }} + - {{ .Release.Namespace }} selector: - matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} - app.kubernetes.io/component: metrics - {{- if .Values.metrics.serviceMonitor.selector }} - {{- include "common.tplvalues.render" (dict "value" .Values.metrics.serviceMonitor.selector "context" $) | nindent 6 }} - {{- end }} + matchLabels: + app: {{ include "mysql.fullname" . }} + release: {{ .Release.Name }} {{- end }} diff --git a/deployment/charts/mysql/templates/svc.yaml b/deployment/charts/mysql/templates/svc.yaml new file mode 100644 index 0000000..3185193 --- /dev/null +++ b/deployment/charts/mysql/templates/svc.yaml @@ -0,0 +1,42 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "mysql.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mysql.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" + annotations: +{{- if .Values.service.annotations }} +{{ toYaml .Values.service.annotations | indent 4 }} +{{- end }} +{{- if and (.Values.metrics.enabled) (.Values.metrics.annotations) }} +{{ toYaml .Values.metrics.annotations | indent 4 }} +{{- end }} +spec: + type: {{ .Values.service.type }} + {{- if (and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerIP))) }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + ports: + - name: mysql + port: {{ .Values.service.port }} + targetPort: mysql + {{- if .Values.service.nodePort }} + nodePort: {{ .Values.service.nodePort }} + {{- end }} + {{- if .Values.mysqlx.port.enabled }} + - name: mysqlx + port: 33060 + targetPort: mysqlx + protocol: TCP + {{- end }} + {{- if .Values.metrics.enabled }} + - name: metrics + port: 9104 + targetPort: metrics + {{- end }} + selector: + app: {{ template "mysql.fullname" . }} diff --git a/deployment/charts/mysql/templates/tests/test-configmap.yaml b/deployment/charts/mysql/templates/tests/test-configmap.yaml new file mode 100644 index 0000000..ece5a47 --- /dev/null +++ b/deployment/charts/mysql/templates/tests/test-configmap.yaml @@ -0,0 +1,23 @@ +{{- if .Values.testFramework.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "mysql.fullname" . }}-test + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mysql.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: "{{ .Release.Service }}" + release: "{{ .Release.Name }}" +data: + run.sh: |- + {{- if .Values.ssl.enabled | and .Values.mysqlRootPassword }} + @test "Testing SSL MySQL Connection" { + mysql --host={{ template "mysql.fullname" . }} --port={{ .Values.service.port | default "3306" }} --ssl-cert=/ssl/server-cert.pem --ssl-key=ssl/server-key.pem -u root -p{{ .Values.mysqlRootPassword }} + } + {{- else if .Values.mysqlRootPassword }} + @test "Testing MySQL Connection" { + mysql --host={{ template "mysql.fullname" . }} --port={{ .Values.service.port | default "3306" }} -u root -p{{ .Values.mysqlRootPassword }} + } + {{- end }} +{{- end }} diff --git a/deployment/charts/mysql/templates/tests/test.yaml b/deployment/charts/mysql/templates/tests/test.yaml new file mode 100644 index 0000000..1771cd0 --- /dev/null +++ b/deployment/charts/mysql/templates/tests/test.yaml @@ -0,0 +1,59 @@ +{{- if .Values.testFramework.enabled }} +apiVersion: v1 +kind: Pod +metadata: + name: {{ template "mysql.fullname" . }}-test + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mysql.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: "{{ .Release.Service }}" + release: "{{ .Release.Name }}" + annotations: + "helm.sh/hook": test-success +spec: + {{- if .Values.testFramework.securityContext }} + securityContext: {{ toYaml .Values.testFramework.securityContext | nindent 4 }} + {{- end }} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: + {{- range .Values.imagePullSecrets }} + - name: {{ . }} + {{- end}} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 4 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 4 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 4 }} + {{- end }} + containers: + - name: {{ .Release.Name }}-test + image: "{{ .Values.testFramework.image }}:{{ .Values.testFramework.tag }}" + imagePullPolicy: "{{ .Values.testFramework.imagePullPolicy}}" + command: ["/opt/bats/bin/bats", "-t", "/tests/run.sh"] + volumeMounts: + - mountPath: /tests + name: tests + readOnly: true + {{- if .Values.ssl.enabled }} + - name: certificates + mountPath: /ssl + {{- end }} + volumes: + - name: tests + configMap: + name: {{ template "mysql.fullname" . }}-test + {{- if .Values.ssl.enabled }} + - name: certificates + secret: + secretName: {{ .Values.ssl.secret }} + {{- end }} + restartPolicy: Never +{{- end }} diff --git a/deployment/charts/mysql/values.schema.json b/deployment/charts/mysql/values.schema.json deleted file mode 100644 index df59156..0000000 --- a/deployment/charts/mysql/values.schema.json +++ /dev/null @@ -1,195 +0,0 @@ -{ - "$schema": "http://json-schema.org/schema#", - "type": "object", - "properties": { - "architecture": { - "type": "string", - "title": "MySQL architecture", - "form": true, - "description": "Allowed values: `standalone` or `replication`", - "enum": ["standalone", "replication"] - }, - "auth": { - "type": "object", - "title": "Authentication configuration", - "form": true, - "required": ["username", "password"], - "if": { - "properties": { - "createDatabase": { "enum": [ true ] } - } - }, - "then": { - "properties": { - "database": { - "pattern": "[a-zA-Z0-9]{1,64}" - } - } - }, - "properties": { - "rootPassword": { - "type": "string", - "title": "MySQL root password", - "description": "Defaults to a random 10-character alphanumeric string if not set" - }, - "database": { - "type": "string", - "title": "MySQL custom database name", - "maxLength": 64 - }, - "username": { - "type": "string", - "title": "MySQL custom username" - }, - "password": { - "type": "string", - "title": "MySQL custom password" - }, - "replicationUser": { - "type": "string", - "title": "MySQL replication username" - }, - "replicationPassword": { - "type": "string", - "title": "MySQL replication password" - }, - "createDatabase": { - "type": "boolean", - "title": "MySQL create custom database" - } - } - }, - "primary": { - "type": "object", - "title": "Primary database configuration", - "form": true, - "properties": { - "podSecurityContext": { - "type": "object", - "title": "MySQL primary Pod security context", - "properties": { - "enabled": { - "type": "boolean", - "default": false - }, - "fsGroup": { - "type": "integer", - "default": 1001, - "hidden": { - "value": false, - "path": "primary/podSecurityContext/enabled" - } - } - } - }, - "containerSecurityContext": { - "type": "object", - "title": "MySQL primary container security context", - "properties": { - "enabled": { - "type": "boolean", - "default": false - }, - "runAsUser": { - "type": "integer", - "default": 1001, - "hidden": { - "value": false, - "path": "primary/containerSecurityContext/enabled" - } - } - } - }, - "persistence": { - "type": "object", - "title": "Enable persistence using Persistent Volume Claims", - "properties": { - "enabled": { - "type": "boolean", - "default": true, - "title": "If true, use a Persistent Volume Claim, If false, use emptyDir" - }, - "size": { - "type": "string", - "title": "Persistent Volume Size", - "form": true, - "render": "slider", - "sliderMin": 1, - "sliderUnit": "Gi", - "hidden": { - "value": false, - "path": "primary/persistence/enabled" - } - } - } - } - } - }, - "secondary": { - "type": "object", - "title": "Secondary database configuration", - "form": true, - "properties": { - "podSecurityContext": { - "type": "object", - "title": "MySQL secondary Pod security context", - "properties": { - "enabled": { - "type": "boolean", - "default": false - }, - "fsGroup": { - "type": "integer", - "default": 1001, - "hidden": { - "value": false, - "path": "secondary/podSecurityContext/enabled" - } - } - } - }, - "containerSecurityContext": { - "type": "object", - "title": "MySQL secondary container security context", - "properties": { - "enabled": { - "type": "boolean", - "default": false - }, - "runAsUser": { - "type": "integer", - "default": 1001, - "hidden": { - "value": false, - "path": "secondary/containerSecurityContext/enabled" - } - } - } - }, - "persistence": { - "type": "object", - "title": "Enable persistence using Persistent Volume Claims", - "properties": { - "enabled": { - "type": "boolean", - "default": true, - "title": "If true, use a Persistent Volume Claim, If false, use emptyDir" - }, - "size": { - "type": "string", - "title": "Persistent Volume Size", - "form": true, - "render": "slider", - "sliderMin": 1, - "sliderUnit": "Gi", - "hidden": { - "value": false, - "path": "secondary/persistence/enabled" - } - } - } - } - } - } - } -} diff --git a/deployment/charts/mysql/values.yaml b/deployment/charts/mysql/values.yaml index d010209..68705ed 100644 --- a/deployment/charts/mysql/values.yaml +++ b/deployment/charts/mysql/values.yaml @@ -1,1208 +1,246 @@ -## @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 StorageClass for Persistent Volume(s) +## mysql image version +## ref: https://hub.docker.com/r/library/mysql/tags/ ## -global: - imageRegistry: "" - ## E.g. - ## imagePullSecrets: - ## - myRegistryKeySecretName - ## - imagePullSecrets: [] - storageClass: "" - -## @section Common parameters +image: "mysql" +imageTag: "5.7.30" -## @param kubeVersion Force target Kubernetes version (using Helm capabilities if not set) -## -kubeVersion: "" -## @param nameOverride String to partially override common.names.fullname template (will maintain the release name) -## -nameOverride: "" -## @param fullnameOverride String to fully override common.names.fullname template -## -fullnameOverride: "" -## @param namespaceOverride String to fully override common.names.namespace -## -namespaceOverride: "" -## @param clusterDomain Cluster domain -## -clusterDomain: cluster.local -## @param commonAnnotations Common annotations to add to all MySQL resources (sub-charts are not considered). Evaluated as a template -## -commonAnnotations: {} -## @param commonLabels Common labels to add to all MySQL resources (sub-charts are not considered). Evaluated as a template -## -commonLabels: {} -## @param extraDeploy Array with extra yaml to deploy with the chart. Evaluated as a template -## -extraDeploy: [] +strategy: + type: Recreate -## 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 +busybox: + image: "busybox" + tag: "1.32" -## @section MySQL common parameters +testFramework: + enabled: true + image: "bats/bats" + tag: "1.2.1" + imagePullPolicy: IfNotPresent + securityContext: {} -## Bitnami MySQL image -## ref: https://hub.docker.com/r/bitnami/mysql/tags/ -## @param image.registry MySQL image registry -## @param image.repository MySQL image repository -## @param image.tag MySQL image tag (immutable tags are recommended) -## @param image.digest MySQL image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag -## @param image.pullPolicy MySQL image pull policy -## @param image.pullSecrets Specify docker-registry secret names as an array -## @param image.debug Specify if debug logs should be enabled +## Specify password for root user ## -image: - registry: docker.io - repository: bitnami/mysql - tag: 8.0.31-debian-11-r30 - 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 MySQL architecture (`standalone` or `replication`) +## Default: random 10 character string +# mysqlRootPassword: testing + +## Create a database user ## -architecture: standalone -## MySQL Authentication parameters +# mysqlUser: +## Default: random 10 character string +# mysqlPassword: + +## Allow unauthenticated access, uncomment to enable ## -auth: - ## @param auth.rootPassword Password for the `root` user. Ignored if existing secret is provided - ## ref: https://github.com/bitnami/containers/tree/main/bitnami/mysql#setting-the-root-password-on-first-run - ## - rootPassword: "" - ## @param auth.createDatabase Wheter to create the .Values.auth.database or not - ## ref: https://github.com/bitnami/containers/tree/main/bitnami/mysql#creating-a-database-on-first-run - ## - createDatabase: true - ## @param auth.database Name for a custom database to create - ## ref: https://github.com/bitnami/containers/tree/main/bitnami/mysql#creating-a-database-on-first-run - ## - database: "my_database" - ## @param auth.username Name for a custom user to create - ## ref: https://github.com/bitnami/containers/tree/main/bitnami/mysql#creating-a-database-user-on-first-run - ## - username: "" - ## @param auth.password Password for the new user. Ignored if existing secret is provided - ## - password: "" - ## @param auth.replicationUser MySQL replication user - ## ref: https://github.com/bitnami/containers/tree/main/bitnami/mysql#setting-up-a-replication-cluster - ## - replicationUser: replicator - ## @param auth.replicationPassword MySQL replication user password. Ignored if existing secret is provided - ## - replicationPassword: "" - ## @param auth.existingSecret Use existing secret for password details. The secret has to contain the keys `mysql-root-password`, `mysql-replication-password` and `mysql-password` - ## NOTE: When it's set the auth.rootPassword, auth.password, auth.replicationPassword are ignored. - ## - existingSecret: "" - ## @param auth.usePasswordFiles Mount credentials as files instead of using an environment variable - ## - 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/mysql-root - ## user: /vault/secrets/mysql-user - ## replicator: /vault/secrets/mysql-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." +# mysqlAllowEmptyPassword: true + +## Create a database ## -initdbScripts: {} -## @param initdbScriptsConfigMap ConfigMap with the initdb scripts (Note: Overrides `initdbScripts`) +# mysqlDatabase: + +## Specify an imagePullPolicy (Required) +## It's recommended to change this to 'Always' if the image tag is 'latest' +## ref: http://kubernetes.io/docs/user-guide/images/#updating-images ## -initdbScriptsConfigMap: "" +imagePullPolicy: IfNotPresent -## @section MySQL Primary parameters +## Additionnal arguments that are passed to the MySQL container. +## For example use --default-authentication-plugin=mysql_native_password if older clients need to +## connect to a MySQL 8 instance. +args: [] -primary: - ## @param primary.name Name of the primary database (eg primary, master, leader, ...) - ## - name: primary - ## @param primary.command Override default container command on MySQL Primary container(s) (useful when using custom images) - ## - command: [] - ## @param primary.args Override default container args on MySQL Primary container(s) (useful when using custom images) - ## - args: [] - ## @param primary.lifecycleHooks for the MySQL Primary container(s) to automate configuration before or after startup - ## - lifecycleHooks: {} - ## @param primary.hostAliases Deployment pod host aliases - ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ - ## - hostAliases: [] - ## @param primary.configuration [string] Configure MySQL Primary with a custom my.cnf file - ## ref: https://mysql.com/kb/en/mysql/configuring-mysql-with-mycnf/#example-of-configuration-file - ## - configuration: |- - [mysqld] - default_authentication_plugin=mysql_native_password - skip-name-resolve - explicit_defaults_for_timestamp - basedir=/opt/bitnami/mysql - plugin_dir=/opt/bitnami/mysql/lib/plugin - port=3306 - socket=/opt/bitnami/mysql/tmp/mysql.sock - datadir=/bitnami/mysql/data - tmpdir=/opt/bitnami/mysql/tmp - max_allowed_packet=16M - bind-address=* - pid-file=/opt/bitnami/mysql/tmp/mysqld.pid - log-error=/opt/bitnami/mysql/logs/mysqld.log - character-set-server=UTF8 - collation-server=utf8_general_ci - slow_query_log=0 - slow_query_log_file=/opt/bitnami/mysql/logs/mysqld.log - long_query_time=10.0 +extraVolumes: | + # - name: extras + # emptyDir: {} - [client] - port=3306 - socket=/opt/bitnami/mysql/tmp/mysql.sock - default-character-set=UTF8 - plugin_dir=/opt/bitnami/mysql/lib/plugin +extraVolumeMounts: | + # - name: extras + # mountPath: /usr/share/extras + # readOnly: true - [manager] - port=3306 - socket=/opt/bitnami/mysql/tmp/mysql.sock - pid-file=/opt/bitnami/mysql/tmp/mysqld.pid - ## @param primary.existingConfigmap Name of existing ConfigMap with MySQL Primary configuration. - ## NOTE: When it's set the 'configuration' parameter is ignored - ## - existingConfigmap: "" - ## @param primary.updateStrategy.type Update strategy type for the MySQL primary statefulset - ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies - ## - updateStrategy: - type: RollingUpdate - ## @param primary.podAnnotations Additional pod annotations for MySQL primary pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ - ## - podAnnotations: {} - ## @param primary.podAffinityPreset MySQL 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 MySQL 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 - ## MySQL Primary node affinity preset - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity - ## - nodeAffinityPreset: - ## @param primary.nodeAffinityPreset.type MySQL primary node affinity preset type. Ignored if `primary.affinity` is set. Allowed values: `soft` or `hard` - ## - type: "" - ## @param primary.nodeAffinityPreset.key MySQL 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 MySQL 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 MySQL 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 MySQL primary pods assignment - ## ref: https://kubernetes.io/docs/user-guide/node-selection/ - ## - nodeSelector: {} - ## @param primary.tolerations Tolerations for MySQL primary pods assignment - ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ - ## - tolerations: [] - ## @param primary.priorityClassName MySQL primary pods' priorityClassName - ## - priorityClassName: "" - ## @param primary.runtimeClassName MySQL primary pods' runtimeClassName - ## - runtimeClassName: "" - ## @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.terminationGracePeriodSeconds In seconds, time the given to the MySQL primary pod needs to terminate gracefully - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods - ## - terminationGracePeriodSeconds: "" - ## @param primary.topologySpreadConstraints Topology Spread Constraints for pod assignment - ## https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ - ## The value is evaluated as a template - ## - topologySpreadConstraints: [] - ## @param primary.podManagementPolicy podManagementPolicy to manage scaling operation of MySQL primary pods - ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies - ## - podManagementPolicy: "" - ## MySQL 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 MySQL primary pods - ## @param primary.podSecurityContext.fsGroup Group ID for the mounted volumes' filesystem - ## - podSecurityContext: - enabled: true - fsGroup: 1001 - ## MySQL 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 MySQL primary container securityContext - ## @param primary.containerSecurityContext.runAsUser User ID for the MySQL primary container - ## @param primary.containerSecurityContext.runAsNonRoot Set MySQL primary container's Security Context runAsNonRoot - ## - containerSecurityContext: - enabled: true - runAsUser: 1001 - runAsNonRoot: true - ## MySQL 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 MySQL primary containers - ## @param primary.resources.requests The requested resources for MySQL primary containers - ## - resources: - ## Example: - ## limits: - ## cpu: 250m - ## memory: 256Mi - limits: {} - ## Examples: - ## requests: - ## cpu: 250m - ## 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 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: 5 - periodSeconds: 10 - timeoutSeconds: 1 - failureThreshold: 3 - successThreshold: 1 - ## Configure extra options for readiness probe - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes - ## @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: 5 - periodSeconds: 10 - timeoutSeconds: 1 - failureThreshold: 3 - successThreshold: 1 - ## Configure extra options for startupProbe probe - ## 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: true - initialDelaySeconds: 15 - periodSeconds: 10 - timeoutSeconds: 1 - failureThreshold: 10 - successThreshold: 1 - ## @param primary.customLivenessProbe Override default liveness probe for MySQL primary containers - ## - customLivenessProbe: {} - ## @param primary.customReadinessProbe Override default readiness probe for MySQL primary containers - ## - customReadinessProbe: {} - ## @param primary.customStartupProbe Override default startup probe for MySQL primary containers - ## - customStartupProbe: {} - ## @param primary.extraFlags MySQL 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 MySQL primary containers - ## E.g. - ## extraEnvVars: - ## - name: TZ - ## value: "Europe/Paris" - ## - extraEnvVars: [] - ## @param primary.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for MySQL primary containers - ## - extraEnvVarsCM: "" - ## @param primary.extraEnvVarsSecret Name of existing Secret containing extra env vars for MySQL 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 MySQL primary replicas using a `PersistentVolumeClaim`. If false, use emptyDir - ## - enabled: true - ## @param primary.persistence.existingClaim Name of an existing `PersistentVolumeClaim` for MySQL primary replicas - ## NOTE: When it's set the rest of persistence parameters are ignored - ## - existingClaim: "" - ## @param primary.persistence.subPath The name of a volume's sub path to mount for persistence - ## - subPath: "" - ## @param primary.persistence.storageClass MySQL 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 MySQL primary persistent volume claim annotations - ## - annotations: {} - ## @param primary.persistence.accessModes MySQL primary persistent volume access Modes - ## - accessModes: - - ReadWriteOnce - ## @param primary.persistence.size MySQL 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 MySQL Primary pod(s) - ## - extraVolumes: [] - ## @param primary.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the MySQL Primary container(s) - ## - extraVolumeMounts: [] - ## @param primary.initContainers Add additional init containers for the MySQL Primary pod(s) - ## - initContainers: [] - ## @param primary.sidecars Add additional sidecar containers for the MySQL Primary pod(s) - ## - sidecars: [] - ## MySQL Primary Service parameters - ## - service: - ## @param primary.service.type MySQL Primary K8s service type - ## - type: ClusterIP - ## @param primary.service.ports.mysql MySQL Primary K8s service port - ## - ports: - mysql: 3306 - ## @param primary.service.nodePorts.mysql MySQL Primary K8s service node port - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport - ## - nodePorts: - mysql: "" - ## @param primary.service.clusterIP MySQL Primary K8s service clusterIP IP - ## e.g: - ## clusterIP: None - ## - clusterIP: "" - ## @param primary.service.loadBalancerIP MySQL Primary loadBalancerIP if service type is `LoadBalancer` - ## Set the LoadBalancer service type to internal only - ## 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 Addresses that are allowed when MySQL 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 Additional custom annotations for MySQL primary service - ## - 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: {} - ## Headless service properties - ## - headless: - ## @param primary.service.headless.annotations Additional custom annotations for headless MySQL primary service. - ## - annotations: {} +extraInitContainers: | + # - name: do-something + # image: busybox + # command: ['do', 'something'] - ## MySQL 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 MySQL primary pods - ## - create: false - ## @param primary.pdb.minAvailable Minimum number/percentage of MySQL primary pods that should remain scheduled - ## - minAvailable: 1 - ## @param primary.pdb.maxUnavailable Maximum number/percentage of MySQL primary pods that may be made unavailable - ## - maxUnavailable: "" - ## @param primary.podLabels MySQL Primary pod label. If labels are same as commonLabels , this will take precedence - ## - podLabels: {} +## A string to add extra environment variables +# extraEnvVars: | +# - name: EXTRA_VAR +# value: "extra" -## @section MySQL Secondary parameters +# Optionally specify an array of imagePullSecrets. +# Secrets must be manually created in the namespace. +# ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod +# imagePullSecrets: + # - name: myRegistryKeySecretName -secondary: - ## @param secondary.name Name of the secondary database (eg secondary, slave, ...) - ## - name: secondary - ## @param secondary.replicaCount Number of MySQL secondary replicas - ## - replicaCount: 1 - ## @param secondary.hostAliases Deployment pod host aliases - ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ - ## - hostAliases: [] - ## @param secondary.command Override default container command on MySQL Secondary container(s) (useful when using custom images) - ## - command: [] - ## @param secondary.args Override default container args on MySQL Secondary container(s) (useful when using custom images) - ## - args: [] - ## @param secondary.lifecycleHooks for the MySQL Secondary container(s) to automate configuration before or after startup - ## - lifecycleHooks: {} - ## @param secondary.configuration [string] Configure MySQL Secondary with a custom my.cnf file - ## ref: https://mysql.com/kb/en/mysql/configuring-mysql-with-mycnf/#example-of-configuration-file - ## - configuration: |- - [mysqld] - default_authentication_plugin=mysql_native_password - skip-name-resolve - explicit_defaults_for_timestamp - basedir=/opt/bitnami/mysql - plugin_dir=/opt/bitnami/mysql/lib/plugin - port=3306 - socket=/opt/bitnami/mysql/tmp/mysql.sock - datadir=/bitnami/mysql/data - tmpdir=/opt/bitnami/mysql/tmp - max_allowed_packet=16M - bind-address=* - pid-file=/opt/bitnami/mysql/tmp/mysqld.pid - log-error=/opt/bitnami/mysql/logs/mysqld.log - character-set-server=UTF8 - collation-server=utf8_general_ci - slow_query_log=0 - slow_query_log_file=/opt/bitnami/mysql/logs/mysqld.log - long_query_time=10.0 +## Node selector +## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector +nodeSelector: {} - [client] - port=3306 - socket=/opt/bitnami/mysql/tmp/mysql.sock - default-character-set=UTF8 - plugin_dir=/opt/bitnami/mysql/lib/plugin +## Affinity +## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity +affinity: {} - [manager] - port=3306 - socket=/opt/bitnami/mysql/tmp/mysql.sock - pid-file=/opt/bitnami/mysql/tmp/mysqld.pid - ## @param secondary.existingConfigmap Name of existing ConfigMap with MySQL Secondary configuration. - ## NOTE: When it's set the 'configuration' parameter is ignored - ## - existingConfigmap: "" - ## @param secondary.updateStrategy.type Update strategy type for the MySQL secondary statefulset - ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies - ## - updateStrategy: - type: RollingUpdate - ## @param secondary.podAnnotations Additional pod annotations for MySQL secondary pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ - ## - podAnnotations: {} - ## @param secondary.podAffinityPreset MySQL 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 MySQL 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 - ## Allowed values: soft, hard - ## - podAntiAffinityPreset: soft - ## MySQL Secondary node affinity preset - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity - ## - nodeAffinityPreset: - ## @param secondary.nodeAffinityPreset.type MySQL secondary node affinity preset type. Ignored if `secondary.affinity` is set. Allowed values: `soft` or `hard` - ## - type: "" - ## @param secondary.nodeAffinityPreset.key MySQL 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 MySQL 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 MySQL 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 MySQL secondary pods assignment - ## ref: https://kubernetes.io/docs/user-guide/node-selection/ - ## - nodeSelector: {} - ## @param secondary.tolerations Tolerations for MySQL secondary pods assignment - ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ - ## - tolerations: [] - ## @param secondary.priorityClassName MySQL secondary pods' priorityClassName - ## - priorityClassName: "" - ## @param secondary.runtimeClassName MySQL secondary pods' runtimeClassName - ## - 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.terminationGracePeriodSeconds In seconds, time the given to the MySQL secondary pod needs to terminate gracefully - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods - ## - terminationGracePeriodSeconds: "" - ## @param secondary.topologySpreadConstraints Topology Spread Constraints for pod assignment - ## https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ - ## The value is evaluated as a template - ## - topologySpreadConstraints: [] - ## @param secondary.podManagementPolicy podManagementPolicy to manage scaling operation of MySQL secondary pods - ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies - ## - podManagementPolicy: "" - ## MySQL 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 MySQL secondary pods - ## @param secondary.podSecurityContext.fsGroup Group ID for the mounted volumes' filesystem - ## - podSecurityContext: - enabled: true - fsGroup: 1001 - ## MySQL 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 MySQL secondary container securityContext - ## @param secondary.containerSecurityContext.runAsUser User ID for the MySQL secondary container - ## @param secondary.containerSecurityContext.runAsNonRoot Set MySQL secondary container's Security Context runAsNonRoot - ## - containerSecurityContext: - enabled: true - runAsUser: 1001 - runAsNonRoot: true - ## MySQL 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 MySQL secondary containers - ## @param secondary.resources.requests The requested resources for MySQL secondary containers - ## - resources: - ## Example: - ## limits: - ## cpu: 250m - ## memory: 256Mi - limits: {} - ## Examples: - ## requests: - ## cpu: 250m - ## 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 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: 5 - periodSeconds: 10 - timeoutSeconds: 1 - failureThreshold: 3 - successThreshold: 1 - ## Configure extra options for readiness probe - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes - ## @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: 5 - periodSeconds: 10 - timeoutSeconds: 1 - failureThreshold: 3 - successThreshold: 1 - ## Configure extra options for startupProbe probe - ## 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: true - initialDelaySeconds: 15 - periodSeconds: 10 - timeoutSeconds: 1 - failureThreshold: 15 - successThreshold: 1 - ## @param secondary.customLivenessProbe Override default liveness probe for MySQL secondary containers - ## - customLivenessProbe: {} - ## @param secondary.customReadinessProbe Override default readiness probe for MySQL secondary containers - ## - customReadinessProbe: {} - ## @param secondary.customStartupProbe Override default startup probe for MySQL secondary containers - ## - customStartupProbe: {} - ## @param secondary.extraFlags MySQL 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 An array to add extra environment variables on MySQL secondary containers - ## E.g. - ## extraEnvVars: - ## - name: TZ - ## value: "Europe/Paris" - ## - extraEnvVars: [] - ## @param secondary.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for MySQL secondary containers - ## - extraEnvVarsCM: "" - ## @param secondary.extraEnvVarsSecret Name of existing Secret containing extra env vars for MySQL 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 MySQL secondary replicas using a `PersistentVolumeClaim` - ## - enabled: true - ## @param secondary.persistence.existingClaim Name of an existing `PersistentVolumeClaim` for MySQL secondary replicas - ## NOTE: When it's set the rest of persistence parameters are ignored - ## - existingClaim: "" - ## @param secondary.persistence.subPath The name of a volume's sub path to mount for persistence - ## - subPath: "" - ## @param secondary.persistence.storageClass MySQL 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 MySQL secondary persistent volume claim annotations - ## - annotations: {} - ## @param secondary.persistence.accessModes MySQL secondary persistent volume access Modes - ## - accessModes: - - ReadWriteOnce - ## @param secondary.persistence.size MySQL 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 MySQL secondary pod(s) - ## - extraVolumes: [] - ## @param secondary.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the MySQL secondary container(s) - ## - extraVolumeMounts: [] - ## @param secondary.initContainers Add additional init containers for the MySQL secondary pod(s) - ## - initContainers: [] - ## @param secondary.sidecars Add additional sidecar containers for the MySQL secondary pod(s) - ## - sidecars: [] - ## MySQL Secondary Service parameters - ## - service: - ## @param secondary.service.type MySQL secondary Kubernetes service type - ## - type: ClusterIP - ## @param secondary.service.ports.mysql MySQL secondary Kubernetes service port - ## - ports: - mysql: 3306 - ## @param secondary.service.nodePorts.mysql MySQL secondary Kubernetes service node port - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport - ## - nodePorts: - mysql: "" - ## @param secondary.service.clusterIP MySQL secondary Kubernetes service clusterIP IP - ## e.g: - ## clusterIP: None - ## - clusterIP: "" - ## @param secondary.service.loadBalancerIP MySQL secondary loadBalancerIP if service type is `LoadBalancer` - ## Set the LoadBalancer service type to internal only - ## 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 Addresses that are allowed when MySQL 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 Additional custom annotations for MySQL secondary service - ## - 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: {} - ## Headless service properties - ## - headless: - ## @param secondary.service.headless.annotations Additional custom annotations for headless MySQL secondary service. - ## - annotations: {} +## Tolerations for pod assignment +## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ +## +tolerations: [] - ## MySQL 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 MySQL secondary pods - ## - create: false - ## @param secondary.pdb.minAvailable Minimum number/percentage of MySQL secondary pods that should remain scheduled - ## - minAvailable: 1 - ## @param secondary.pdb.maxUnavailable Maximum number/percentage of MySQL secondary pods that may be made unavailable - ## - maxUnavailable: "" - ## @param secondary.podLabels Additional pod labels for MySQL secondary pods - ## - podLabels: {} +livenessProbe: + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 3 -## @section RBAC parameters +readinessProbe: + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 3 -## MySQL 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 MySQL pods - ## - create: true - ## @param serviceAccount.name Name of the created ServiceAccount - ## If not set and create is true, a name is generated using the mysql.fullname template - ## - name: "" - ## @param serviceAccount.annotations Annotations for MySQL Service Account - ## +## Persist data to a persistent volume +persistence: + enabled: true + ## database data 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: "-" + accessMode: ReadWriteOnce + size: 8Gi annotations: {} - ## @param serviceAccount.automountServiceAccountToken Automount service account token for the server service account - ## - automountServiceAccountToken: true - -## Role Based Access -## ref: https://kubernetes.io/docs/admin/authorization/rbac/ -## -rbac: - ## @param rbac.create Whether to create & use RBAC resources or not - ## - create: false - ## @param rbac.rules Custom RBAC rules to set - ## e.g: - ## rules: - ## - apiGroups: - ## - "" - ## resources: - ## - pods - ## verbs: - ## - get - ## - list - ## - rules: [] - -## @section Network Policy -## MySQL Nework Policy configuration +## Use an alternate scheduler, e.g. "stork". +## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ ## -networkPolicy: - ## @param networkPolicy.enabled Enable creation of NetworkPolicy resources - ## - enabled: false - ## @param networkPolicy.allowExternal The Policy model to apply. - ## When set to false, only pods with the correct - ## client label will have network access to the port MySQL is listening - ## on. When true, MySQL will accept connections from any source - ## (with the correct destination port). - ## - allowExternal: true - ## @param networkPolicy.explicitNamespacesSelector A Kubernetes LabelSelector to explicitly select namespaces from which ingress traffic could be allowed to MySQL - ## If explicitNamespacesSelector is missing or set to {}, only client Pods that are in the networkPolicy's namespace - ## and that match other criteria, the ones that have the good label, can reach the DB. - ## But sometimes, we want the DB to be accessible to clients from other namespaces, in this case, we can use this - ## LabelSelector to select these namespaces, note that the networkPolicy's namespace should also be explicitly added. - ## - ## Example: - ## explicitNamespacesSelector: - ## matchLabels: - ## role: frontend - ## matchExpressions: - ## - {key: role, operator: In, values: [frontend]} - ## - explicitNamespacesSelector: {} - -## @section Volume Permissions parameters +# schedulerName: -## 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` - ## +## Security context +securityContext: 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-r70 - 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/ - ## e.g: - ## pullSecrets: - ## - myRegistryKeySecretName - ## - pullSecrets: [] - ## @param volumePermissions.resources Init container volume-permissions resources - ## - resources: {} - -## @section Metrics parameters + runAsUser: 999 + fsGroup: 999 + +## Configure resource requests and limits +## ref: http://kubernetes.io/docs/user-guide/compute-resources/ +## +resources: + requests: + memory: 256Mi + cpu: 100m + +# Custom mysql configuration files path +configurationFilesPath: /etc/mysql/conf.d/ + +# Custom mysql configuration files used to override default mysql settings +configurationFiles: {} +# mysql.cnf: |- +# [mysqld] +# skip-name-resolve +# ssl-ca=/ssl/ca.pem +# ssl-cert=/ssl/server-cert.pem +# ssl-key=/ssl/server-key.pem + +# Custom mysql init SQL files used to initialize the database +initializationFiles: {} +# first-db.sql: |- +# CREATE DATABASE IF NOT EXISTS first DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; +# second-db.sql: |- +# CREATE DATABASE IF NOT EXISTS second DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; + +# To enaable the mysql X Protocol's port +# .. will expose the port 33060 +# .. Note the X Plugin needs installation +# ref: https://dev.mysql.com/doc/refman/8.0/en/x-plugin-checking-installation.html +mysqlx: + port: + enabled: false -## 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-r76 - 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/ - ## e.g: - ## pullSecrets: - ## - myRegistryKeySecretName - ## - pullSecrets: [] - ## MySQL Prometheus exporter service parameters - ## Mysqld Prometheus exporter liveness and readiness probes - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes - ## @param metrics.service.type Kubernetes service type for MySQL Prometheus Exporter - ## @param metrics.service.port MySQL Prometheus Exporter service port - ## @param metrics.service.annotations [object] Prometheus exporter service annotations - ## - service: - type: ClusterIP - port: 9104 - annotations: - prometheus.io/scrape: "true" - prometheus.io/port: "{{ .Values.metrics.service.port }}" - ## @param metrics.extraArgs.primary Extra args to be passed to mysqld_exporter on Primary pods - ## @param metrics.extraArgs.secondary Extra args to be passed to mysqld_exporter on Secondary pods - ## 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: [] - ## 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 MySQL prometheus exporter containers - ## @param metrics.resources.requests The requested resources for MySQL prometheus exporter containers - ## - resources: - ## Example: - ## limits: - ## cpu: 100m - ## memory: 256Mi - limits: {} - ## Examples: - ## requests: - ## cpu: 100m - ## memory: 256Mi - requests: {} - ## Mysqld Prometheus exporter liveness probe - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-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 - ## + image: prom/mysqld-exporter + imageTag: v0.10.0 + imagePullPolicy: IfNotPresent + resources: {} + annotations: {} + # prometheus.io/scrape: "true" + # prometheus.io/port: "9104" livenessProbe: - enabled: true - initialDelaySeconds: 120 - periodSeconds: 10 - timeoutSeconds: 1 - successThreshold: 1 - failureThreshold: 3 - ## Mysqld Prometheus exporter readiness probe - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-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 - ## + initialDelaySeconds: 15 + timeoutSeconds: 5 readinessProbe: - enabled: true - initialDelaySeconds: 30 - periodSeconds: 10 + initialDelaySeconds: 5 timeoutSeconds: 1 - successThreshold: 1 - failureThreshold: 3 - ## Prometheus Service Monitor - ## ref: https://github.com/coreos/prometheus-operator - ## + flags: [] serviceMonitor: - ## @param metrics.serviceMonitor.enabled Create ServiceMonitor Resource for scraping metrics using PrometheusOperator - ## enabled: false - ## @param metrics.serviceMonitor.namespace Specify the namespace in which the serviceMonitor resource will be created - ## - 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 Specify the 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.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.honorLabels Specify honorLabels parameter to add the scrape endpoint - ## - honorLabels: false - ## @param metrics.serviceMonitor.labels Used to pass Labels that are used by the Prometheus installed in your cluster to select Service Monitors to work with - ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#prometheusspec - ## - labels: {} - ## @param metrics.serviceMonitor.annotations ServiceMonitor annotations - ## - annotations: {} + additionalLabels: {} - ## Prometheus Operator prometheusRule configuration +## Configure the service +## ref: http://kubernetes.io/docs/user-guide/services/ +service: + annotations: {} + ## Specify a service type + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services---service-types + type: ClusterIP + port: 3306 + # nodePort: 32000 + # loadBalancerIP: + +## Pods Service Account +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +serviceAccount: + ## Specifies whether a ServiceAccount should be created ## - prometheusRule: - ## @param metrics.prometheusRule.enabled 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: Mysql-Down - ## expr: absent(up{job="mysql"} == 1) - ## for: 5m - ## labels: - ## severity: warning - ## service: mariadb - ## annotations: - ## message: 'MariaDB instance {{`{{`}} $labels.instance {{`}}`}} is down' - ## summary: MariaDB instance is down - ## - rules: [] + create: false + ## The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the mariadb.fullname template + # name: + +ssl: + enabled: false + secret: mysql-ssl-certs + certificates: +# - name: mysql-ssl-certs +# ca: |- +# -----BEGIN CERTIFICATE----- +# ... +# -----END CERTIFICATE----- +# cert: |- +# -----BEGIN CERTIFICATE----- +# ... +# -----END CERTIFICATE----- +# key: |- +# -----BEGIN RSA PRIVATE KEY----- +# ... +# -----END RSA PRIVATE KEY----- + +## Populates the 'TZ' system timezone environment variable +## ref: https://dev.mysql.com/doc/refman/5.7/en/time-zone-support.html +## +## Default: nil (mysql will use image's default timezone, normally UTC) +## Example: 'Australia/Sydney' +# timezone: + +# Deployment Annotations +deploymentAnnotations: {} + +# To be added to the database server pod(s) +podAnnotations: {} +podLabels: {} + +## Set pod priorityClassName +# priorityClassName: {} + + +## Init container resources defaults +initContainer: + resources: + requests: + memory: 10Mi + cpu: 10m diff --git a/deployment/charts/nginx-ingress/.helmignore b/deployment/charts/nginx-ingress/.helmignore new file mode 100644 index 0000000..c1347c2 --- /dev/null +++ b/deployment/charts/nginx-ingress/.helmignore @@ -0,0 +1,2 @@ +# Patterns to ignore when building packages. +*.png diff --git a/deployment/charts/nginx-ingress/Chart.yaml b/deployment/charts/nginx-ingress/Chart.yaml new file mode 100644 index 0000000..892a14a --- /dev/null +++ b/deployment/charts/nginx-ingress/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v2 +appVersion: 3.0.1 +description: NGINX Ingress Controller +home: https://github.com/nginxinc/kubernetes-ingress +icon: https://raw.githubusercontent.com/nginxinc/kubernetes-ingress/v3.0.1/deployments/helm-chart/chart-icon.png +keywords: +- ingress +- nginx +kubeVersion: '>= 1.21.0-0' +maintainers: +- email: kubernetes@nginx.com + name: nginxinc +name: nginx-ingress +sources: +- https://github.com/nginxinc/kubernetes-ingress/tree/v3.0.1/deployments/helm-chart +type: application +version: 0.16.1 diff --git a/deployment/charts/nginx-ingress/README.md b/deployment/charts/nginx-ingress/README.md new file mode 100644 index 0000000..054eba2 --- /dev/null +++ b/deployment/charts/nginx-ingress/README.md @@ -0,0 +1,274 @@ +# NGINX Ingress Controller Helm Chart + +## Introduction + +This chart deploys the NGINX Ingress Controller in your Kubernetes cluster. + +## Prerequisites + + - A [Kubernetes Version Supported by the Ingress Controller](https://docs.nginx.com/nginx-ingress-controller/technical-specifications/#supported-kubernetes-versions) + - Helm 3.0+. + - Git. + - If you’d like to use NGINX Plus: + - To pull from the F5 Container registry, configure a docker registry secret using your JWT token from the MyF5 portal by following the instructions from [here](https://docs.nginx.com/nginx-ingress-controller/installation/using-the-jwt-token-docker-secret). Make sure to specify the secret using `controller.serviceAccount.imagePullSecretName` parameter. + - Alternatively, pull an Ingress Controller image with NGINX Plus and push it to your private registry by following the instructions from [here](https://docs.nginx.com/nginx-ingress-controller/installation/pulling-ingress-controller-image). + - Alternatively, you can build an Ingress Controller image with NGINX Plus and push it to your private registry by following the instructions from [here](https://docs.nginx.com/nginx-ingress-controller/installation/building-ingress-controller-image). + - Update the `controller.image.repository` field of the `values-plus.yaml` accordingly. + - If you’d like to use App Protect DoS, please install App Protect DoS Arbitrator helm chart. Make sure to install in the same namespace as the NGINX Ingress Controller. Note that if you install multiple NGINX Ingress Controllers in the same namespace, they will need to share the same Arbitrator because it is not possible to install more than one Arbitrator in a single namespace. + + +## Getting the Chart Sources + +This step is required if you're installing the chart using its sources. Additionally, the step is also required for managing the custom resource definitions (CRDs), which the Ingress Controller requires by default, or for upgrading/deleting the CRDs. + +1. Clone the Ingress Controller repo: + ```console + $ git clone https://github.com/nginxinc/kubernetes-ingress --branch v3.0.1 + ``` + **Note**: If you want to use the experimental repository (`edge`), remove the `--branch` flag and value. + +2. Change your working directory to /deployments/helm-chart: + ```console + $ cd kubernetes-ingress/deployments/helm-chart + ``` + +## Adding the Helm Repository + +This step is required if you're installing the chart via the helm repository. + +```console +$ helm repo add nginx-stable https://helm.nginx.com/stable +$ helm repo update +``` + +**Note**: If you want to use the experimental repository, replace `stable` with `edge`. + +## Installing the Chart + +### Installing the CRDs + +By default, the Ingress Controller requires a number of custom resource definitions (CRDs) installed in the cluster. The Helm client will install those CRDs. If the CRDs are not installed, the Ingress Controller pods will not become `Ready`. + +If you do not use the custom resources that require those CRDs (which corresponds to `controller.enableCustomResources` set to `false` and `controller.appprotect.enable` set to `false` and `controller.appprotectdos.enable` set to `false`), the installation of the CRDs can be skipped by specifying `--skip-crds` for the helm install command. + +### Installing via Helm Repository + +To install the chart with the release name my-release (my-release is the name that you choose): + +For NGINX: +```console +$ helm install my-release nginx-stable/nginx-ingress +``` + +For NGINX Plus: (assuming you have pushed the Ingress Controller image `nginx-plus-ingress` to your private registry `myregistry.example.com`) +```console +$ helm install my-release nginx-stable/nginx-ingress --set controller.image.repository=myregistry.example.com/nginx-plus-ingress --set controller.nginxplus=true +``` + +**Note**: If you want to use the experimental repository, replace `stable` with `edge` and add the `--devel` flag. + +### Installing Using Chart Sources + +To install the chart with the release name my-release (my-release is the name that you choose): + +For NGINX: +```console +$ helm install my-release . +``` + +For NGINX Plus: +```console +$ helm install my-release -f values-plus.yaml . +``` + +**Note**: If you want to use the experimental repository, replace the value in the `tag` field inside the yaml files with `edge`. + +The command deploys the Ingress Controller in your Kubernetes cluster in the default configuration. The configuration section lists the parameters that can be configured during installation. + +When deploying the Ingress Controller, make sure to use your own TLS certificate and key for the default server rather than the default pre-generated ones. Read the [Configuration](#Configuration) section below to see how to configure a TLS certificate and key for the default server. Note that the default server returns the Not Found page with the 404 status code for all requests for domains for which there are no Ingress rules defined. + +## Upgrading the Chart + +### Upgrading the CRDs + +Helm does not upgrade the CRDs during a release upgrade. Before you upgrade a release, run the following command to upgrade the CRDs: + +```console +$ kubectl apply -f crds/ +``` +> **Note**: The following warning is expected and can be ignored: `Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply`. + +> **Note**: Make sure to check the [release notes](https://www.github.com/nginxinc/kubernetes-ingress/releases) for a new release for any special upgrade procedures. + +### Upgrading the Release + +To upgrade the release `my-release`: + +#### Upgrade Using Chart Sources: + +```console +$ helm upgrade my-release . +``` + +#### Upgrade via Helm Repository: + +```console +$ helm upgrade my-release nginx-stable/nginx-ingress +``` + +## Uninstalling the Chart + +### Uninstalling the Release + +To uninstall/delete the release `my-release`: + +```console +$ helm uninstall my-release +``` +The command removes all the Kubernetes components associated with the release and deletes the release. + +### Uninstalling the CRDs + +Uninstalling the release does not remove the CRDs. To remove the CRDs, run: + +```console +$ kubectl delete -f crds/ +``` +> **Note**: This command will delete all the corresponding custom resources in your cluster across all namespaces. Please ensure there are no custom resources that you want to keep and there are no other Ingress Controller releases running in the cluster. + +## Running Multiple Ingress Controllers + +If you are running multiple Ingress Controller releases in your cluster with enabled custom resources, the releases will share a single version of the CRDs. As a result, make sure that the Ingress Controller versions match the version of the CRDs. Additionally, when uninstalling a release, ensure that you don’t remove the CRDs until there are no other Ingress Controller releases running in the cluster. + +See [running multiple Ingress Controllers](https://docs.nginx.com/nginx-ingress-controller/installation/running-multiple-ingress-controllers/) for more details. + +## Configuration + +The following tables lists the configurable parameters of the NGINX Ingress Controller chart and their default values. + +Parameter | Description | Default +--- | --- | --- +`controller.name` | The name of the Ingress Controller daemonset or deployment. | Autogenerated +`controller.kind` | The kind of the Ingress Controller installation - deployment or daemonset. | deployment +`controller.annotations` | Allows for setting of `annotations` for deployment or daemonset. | {} +`controller.nginxplus` | Deploys the Ingress Controller for NGINX Plus. | false +`controller.nginxReloadTimeout` | The timeout in milliseconds which the Ingress Controller will wait for a successful NGINX reload after a change or at the initial start. | 60000 +`controller.hostNetwork` | Enables the Ingress Controller pods to use the host's network namespace. | false +`controller.dnsPolicy` | DNS policy for the Ingress Controller pods. | ClusterFirst +`controller.nginxDebug` | Enables debugging for NGINX. Uses the `nginx-debug` binary. Requires `error-log-level: debug` in the ConfigMap via `controller.config.entries`. | false +`controller.logLevel` | The log level of the Ingress Controller. | 1 +`controller.image.digest ` | The image digest of the Ingress Controller. | None +`controller.image.repository` | The image repository of the Ingress Controller. | nginx/nginx-ingress +`controller.image.tag` | The tag of the Ingress Controller image. | 3.0.1 +`controller.image.pullPolicy` | The pull policy for the Ingress Controller image. | IfNotPresent +`controller.lifecycle` | The lifecycle of the Ingress Controller pods. | {} +`controller.customConfigMap` | The name of the custom ConfigMap used by the Ingress Controller. If set, then the default config is ignored. | "" +`controller.config.name` | The name of the ConfigMap used by the Ingress Controller. | Autogenerated +`controller.config.annotations` | The annotations of the Ingress Controller configmap. | {} +`controller.config.entries` | The entries of the ConfigMap for customizing NGINX configuration. See [ConfigMap resource docs](https://docs.nginx.com/nginx-ingress-controller/configuration/global-configuration/configmap-resource/) for the list of supported ConfigMap keys. | {} +`controller.customPorts` | A list of custom ports to expose on the NGINX Ingress Controller pod. Follows the conventional Kubernetes yaml syntax for container ports. | [] +`controller.defaultTLS.cert` | The base64-encoded TLS certificate for the default HTTPS server. **Note:** By default, a pre-generated self-signed certificate is used. It is recommended that you specify your own certificate. Alternatively, omitting the default server secret completely will configure NGINX to reject TLS connections to the default server. | A pre-generated self-signed certificate. +`controller.defaultTLS.key` | The base64-encoded TLS key for the default HTTPS server. **Note:** By default, a pre-generated key is used. It is recommended that you specify your own key. Alternatively, omitting the default server secret completely will configure NGINX to reject TLS connections to the default server. | A pre-generated key. +`controller.defaultTLS.secret` | The secret with a TLS certificate and key for the default HTTPS server. The value must follow the following format: `/`. Used as an alternative to specifying a certificate and key using `controller.defaultTLS.cert` and `controller.defaultTLS.key` parameters. **Note:** Alternatively, omitting the default server secret completely will configure NGINX to reject TLS connections to the default server. | None +`controller.wildcardTLS.cert` | The base64-encoded TLS certificate for every Ingress/VirtualServer host that has TLS enabled but no secret specified. If the parameter is not set, for such Ingress/VirtualServer hosts NGINX will break any attempt to establish a TLS connection. | None +`controller.wildcardTLS.key` | The base64-encoded TLS key for every Ingress/VirtualServer host that has TLS enabled but no secret specified. If the parameter is not set, for such Ingress/VirtualServer hosts NGINX will break any attempt to establish a TLS connection. | None +`controller.wildcardTLS.secret` | The secret with a TLS certificate and key for every Ingress/VirtualServer host that has TLS enabled but no secret specified. The value must follow the following format: `/`. Used as an alternative to specifying a certificate and key using `controller.wildcardTLS.cert` and `controller.wildcardTLS.key` parameters. | None +`controller.nodeSelector` | The node selector for pod assignment for the Ingress Controller pods. | {} +`controller.terminationGracePeriodSeconds` | The termination grace period of the Ingress Controller pod. | 30 +`controller.tolerations` | The tolerations of the Ingress Controller pods. | [] +`controller.affinity` | The affinity of the Ingress Controller pods. | {} +`controller.topologySpreadConstraints` | The topology spread constraints of the Ingress controller pods. | {} +`controller.volumes` | The volumes of the Ingress Controller pods. | [] +`controller.volumeMounts` | The volumeMounts of the Ingress Controller pods. | [] +`controller.initContainers` | InitContainers for the Ingress Controller pods. | [] +`controller.extraContainers` | Extra (eg. sidecar) containers for the Ingress Controller pods. | [] +`controller.resources` | The resources of the Ingress Controller pods. | requests: cpu=100m,memory=128Mi +`controller.replicaCount` | The number of replicas of the Ingress Controller deployment. | 1 +`controller.ingressClass` | A class of the Ingress Controller. An IngressClass resource with the name equal to the class must be deployed. Otherwise, the Ingress Controller will fail to start. The Ingress Controller only processes resources that belong to its class - i.e. have the "ingressClassName" field resource equal to the class. The Ingress Controller processes all the VirtualServer/VirtualServerRoute/TransportServer resources that do not have the "ingressClassName" field for all versions of kubernetes. | nginx +`controller.setAsDefaultIngress` | New Ingresses without an `"ingressClassName"` field specified will be assigned the class specified in `controller.ingressClass`. | false +`controller.watchNamespace` | Comma separated list of namespaces the Ingress Controller should watch for resources. By default the Ingress Controller watches all namespaces. Mutually exclusive with `controller.watchNamespaceLabel`. Please note that if configuring multiple namespaces using the Helm cli `--set` option, the string needs to wrapped in double quotes and the commas escaped using a backslash - e.g. `--set controller.watchNamespace="default\,nginx-ingress"`. | "" +`controller.watchNamespaceLabel` | Configures the Ingress Controller to watch only those namespaces with label foo=bar. By default the Ingress Controller watches all namespaces. Mutually exclusive with `controller.watchNamespace`. | "" +`controller.watchSecretNamespace` | Comma separated list of namespaces the Ingress Controller should watch for resources of type Secret. If this arg is not configured, the Ingress Controller watches the same namespaces for all resources. See `controller.watchNamespace` and `controller.watchNamespaceLabel`. Please note that if configuring multiple namespaces using the Helm cli `--set` option, the string needs to wrapped in double quotes and the commas escaped using a backslash - e.g. `--set controller.watchSecretNamespace="default\,nginx-ingress"`. | "" +`controller.enableCustomResources` | Enable the custom resources. | true +`controller.enablePreviewPolicies` | Enable preview policies. This parameter is deprecated. To enable OIDC Policies please use `controller.enableOIDC` instead. | false +`controller.enableOIDC` | Enable OIDC policies. | false +`controller.enableTLSPassthrough` | Enable TLS Passthrough on port 443. Requires `controller.enableCustomResources`. | false +`controller.enableCertManager` | Enable x509 automated certificate management for VirtualServer resources using cert-manager (cert-manager.io). Requires `controller.enableCustomResources`. | false +`controller.enableExternalDNS` | Enable integration with ExternalDNS for configuring public DNS entries for VirtualServer resources using [ExternalDNS](https://github.com/kubernetes-sigs/external-dns). Requires `controller.enableCustomResources`. | false +`controller.globalConfiguration.create` | Creates the GlobalConfiguration custom resource. Requires `controller.enableCustomResources`. | false +`controller.globalConfiguration.spec` | The spec of the GlobalConfiguration for defining the global configuration parameters of the Ingress Controller. | {} +`controller.enableSnippets` | Enable custom NGINX configuration snippets in Ingress, VirtualServer, VirtualServerRoute and TransportServer resources. | false +`controller.healthStatus` | Add a location "/nginx-health" to the default server. The location responds with the 200 status code for any request. Useful for external health-checking of the Ingress Controller. | false +`controller.healthStatusURI` | Sets the URI of health status location in the default server. Requires `controller.healthStatus`. | "/nginx-health" +`controller.nginxStatus.enable` | Enable the NGINX stub_status, or the NGINX Plus API. | true +`controller.nginxStatus.port` | Set the port where the NGINX stub_status or the NGINX Plus API is exposed. | 8080 +`controller.nginxStatus.allowCidrs` | Add IP/CIDR blocks to the allow list for NGINX stub_status or the NGINX Plus API. Separate multiple IP/CIDR by commas. | 127.0.0.1,::1 +`controller.priorityClassName` | The PriorityClass of the Ingress Controller pods. | None +`controller.service.create` | Creates a service to expose the Ingress Controller pods. | true +`controller.service.type` | The type of service to create for the Ingress Controller. | LoadBalancer +`controller.service.externalTrafficPolicy` | The externalTrafficPolicy of the service. The value Local preserves the client source IP. | Local +`controller.service.annotations` | The annotations of the Ingress Controller service. | {} +`controller.service.extraLabels` | The extra labels of the service. | {} +`controller.service.loadBalancerIP` | The static IP address for the load balancer. Requires `controller.service.type` set to `LoadBalancer`. The cloud provider must support this feature. | "" +`controller.service.externalIPs` | The list of external IPs for the Ingress Controller service. | [] +`controller.service.loadBalancerSourceRanges` | The IP ranges (CIDR) that are allowed to access the load balancer. Requires `controller.service.type` set to `LoadBalancer`. The cloud provider must support this feature. | [] +`controller.service.name` | The name of the service. | Autogenerated +`controller.service.customPorts` | A list of custom ports to expose through the Ingress Controller service. Follows the conventional Kubernetes yaml syntax for service ports. | [] +`controller.service.httpPort.enable` | Enables the HTTP port for the Ingress Controller service. | true +`controller.service.httpPort.port` | The HTTP port of the Ingress Controller service. | 80 +`controller.service.httpPort.nodePort` | The custom NodePort for the HTTP port. Requires `controller.service.type` set to `NodePort`. | "" +`controller.service.httpPort.targetPort` | The target port of the HTTP port of the Ingress Controller service. | 80 +`controller.service.httpsPort.enable` | Enables the HTTPS port for the Ingress Controller service. | true +`controller.service.httpsPort.port` | The HTTPS port of the Ingress Controller service. | 443 +`controller.service.httpsPort.nodePort` | The custom NodePort for the HTTPS port. Requires `controller.service.type` set to `NodePort`. | "" +`controller.service.httpsPort.targetPort` | The target port of the HTTPS port of the Ingress Controller service. | 443 +`controller.serviceAccount.annotations` | The annotations of the Ingress Controller service account. | {} +`controller.serviceAccount.name` | The name of the service account of the Ingress Controller pods. Used for RBAC. | Autogenerated +`controller.serviceAccount.imagePullSecretName` | The name of the secret containing docker registry credentials. Secret must exist in the same namespace as the helm release. | "" +`controller.serviceMonitor.name` | The name of the serviceMonitor. | Autogenerated +`controller.serviceMonitor.create` | Create a ServiceMonitor custom resource. | false +`controller.serviceMonitor.labels` | Kubernetes object labels to attach to the serviceMonitor object. | "" +`controller.serviceMonitor.selectorMatchLabels` | A set of labels to allow the selection of endpoints for the ServiceMonitor. | "" +`controller.serviceMonitor.endpoints` | A list of endpoints allowed as part of this ServiceMonitor. | "" +`controller.reportIngressStatus.enable` | Updates the address field in the status of Ingress resources with an external address of the Ingress Controller. You must also specify the source of the external address either through an external service via `controller.reportIngressStatus.externalService`, `controller.reportIngressStatus.ingressLink` or the `external-status-address` entry in the ConfigMap via `controller.config.entries`. **Note:** `controller.config.entries.external-status-address` takes precedence over the others. | true +`controller.reportIngressStatus.externalService` | Specifies the name of the service with the type LoadBalancer through which the Ingress Controller is exposed externally. The external address of the service is used when reporting the status of Ingress, VirtualServer and VirtualServerRoute resources. `controller.reportIngressStatus.enable` must be set to `true`. The default is autogenerated and enabled when `controller.service.create` is set to `true` and `controller.service.type` is set to `LoadBalancer`. | Autogenerated +`controller.reportIngressStatus.ingressLink` | Specifies the name of the IngressLink resource, which exposes the Ingress Controller pods via a BIG-IP system. The IP of the BIG-IP system is used when reporting the status of Ingress, VirtualServer and VirtualServerRoute resources. `controller.reportIngressStatus.enable` must be set to `true`. | "" +`controller.reportIngressStatus.enableLeaderElection` | Enable Leader election to avoid multiple replicas of the controller reporting the status of Ingress resources. `controller.reportIngressStatus.enable` must be set to `true`. | true +`controller.reportIngressStatus.leaderElectionLockName` | Specifies the name of the ConfigMap, within the same namespace as the controller, used as the lock for leader election. controller.reportIngressStatus.enableLeaderElection must be set to true. | Autogenerated +`controller.reportIngressStatus.annotations` | The annotations of the leader election configmap. | {} +`controller.pod.annotations` | The annotations of the Ingress Controller pod. | {} +`controller.pod.extraLabels` | The additional extra labels of the Ingress Controller pod. | {} +`controller.appprotect.enable` | Enables the App Protect WAF module in the Ingress Controller. | false +`controller.appprotectdos.enable` | Enables the App Protect DoS module in the Ingress Controller. | false +`controller.appprotectdos.debug` | Enable debugging for App Protect DoS. | false +`controller.appprotectdos.maxDaemons` | Max number of ADMD instances. | 1 +`controller.appprotectdos.maxWorkers` | Max number of nginx processes to support. | Number of CPU cores in the machine +`controller.appprotectdos.memory` | RAM memory size to consume in MB. | 50% of free RAM in the container or 80MB, the smaller +`controller.readyStatus.enable` | Enables the readiness endpoint `"/nginx-ready"`. The endpoint returns a success code when NGINX has loaded all the config after the startup. This also configures a readiness probe for the Ingress Controller pods that uses the readiness endpoint. | true +`controller.readyStatus.port` | The HTTP port for the readiness endpoint. | 8081 +`controller.readyStatus.initialDelaySeconds` | The number of seconds after the Ingress Controller pod has started before readiness probes are initiated. | 0 +`controller.enableLatencyMetrics` | Enable collection of latency metrics for upstreams. Requires `prometheus.create`. | false +`controller.minReadySeconds` | Specifies the minimum number of seconds for which a newly created Pod should be ready without any of its containers crashing, for it to be considered available. [docs](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#min-ready-seconds) | 0 +`controller.autoscaling.enabled` | Enables HorizontalPodAutoscaling. | false +`controller.autoscaling.annotations` | The annotations of the Ingress Controller HorizontalPodAutoscaler. | {} +`controller.autoscaling.minReplicas` | Minimum number of replicas for the HPA. | 1 +`controller.autoscaling.maxReplicas` | Maximum number of replicas for the HPA. | 3 +`controller.autoscaling.targetCPUUtilizationPercentage` | The target CPU utilization percentage. | 50 +`controller.autoscaling.targetMemoryUtilizationPercentage` | The target memory utilization percentage. | 50 +`controller.strategy` | Specifies the strategy used to replace old Pods by new ones. [docs](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy) | {} +`controller.disableIPV6` | Disable IPV6 listeners explicitly for nodes that do not support the IPV6 stack. | false +`rbac.create` | Configures RBAC. | true +`prometheus.create` | Expose NGINX or NGINX Plus metrics in the Prometheus format. | false +`prometheus.port` | Configures the port to scrape the metrics. | 9113 +`prometheus.scheme` | Configures the HTTP scheme to use for connections to the Prometheus endpoint. | http +`prometheus.secret` | The namespace / name of a Kubernetes TLS Secret. If specified, this secret is used to secure the Prometheus endpoint with TLS connections. | "" +`serviceInsight.create` | Expose NGINX Plus Service Insight endpoint. | false +`serviceInsight.port` | Configures the port to expose endpoints. | 9114 +`serviceInsight.scheme` | Configures the HTTP scheme to use for connections to the Service Insight endpoint. | http +`serviceInsight.secret` | The namespace / name of a Kubernetes TLS Secret. If specified, this secret is used to secure the Service Insight endpoint with TLS connections. | "" +`nginxServiceMesh.enable` | Enable integration with NGINX Service Mesh. See the NGINX Service Mesh [docs](https://docs.nginx.com/nginx-service-mesh/tutorials/kic/deploy-with-kic/) for more details. Requires `controller.nginxplus`. | false +`nginxServiceMesh.enableEgress` | Enable NGINX Service Mesh workloads to route egress traffic through the Ingress Controller. See the NGINX Service Mesh [docs](https://docs.nginx.com/nginx-service-mesh/tutorials/kic/deploy-with-kic/#enabling-egress) for more details. Requires `nginxServiceMesh.enable`. | false + +## Notes +* The values-icp.yaml file is used for deploying the Ingress Controller on IBM Cloud Private. See the [blog post](https://www.nginx.com/blog/nginx-ingress-controller-ibm-cloud-private/) for more details. +* The values-nsm.yaml file is used for deploying the Ingress Controller with NGINX Service Mesh. See the NGINX Service Mesh [docs](https://docs.nginx.com/nginx-service-mesh/tutorials/kic/deploy-with-kic/) for more details. diff --git a/deployment/charts/nginx-ingress/crds/appprotect.f5.com_aplogconfs.yaml b/deployment/charts/nginx-ingress/crds/appprotect.f5.com_aplogconfs.yaml new file mode 100644 index 0000000..53b7fb4 --- /dev/null +++ b/deployment/charts/nginx-ingress/crds/appprotect.f5.com_aplogconfs.yaml @@ -0,0 +1,80 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.10.0 + creationTimestamp: null + name: aplogconfs.appprotect.f5.com +spec: + group: appprotect.f5.com + names: + kind: APLogConf + listKind: APLogConfList + plural: aplogconfs + singular: aplogconf + preserveUnknownFields: false + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: APLogConf is the Schema for the APLogConfs API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: APLogConfSpec defines the desired state of APLogConf + properties: + content: + properties: + escaping_characters: + items: + properties: + from: + type: string + to: + type: string + type: object + type: array + format: + enum: + - splunk + - arcsight + - default + - user-defined + - grpc + type: string + format_string: + type: string + list_delimiter: + type: string + list_prefix: + type: string + list_suffix: + type: string + max_message_size: + pattern: ^([1-9]|[1-5][0-9]|6[0-4])k$ + type: string + max_request_size: + pattern: ^([1-9]|[1-9][0-9]|[1-9][0-9]{2}|1[0-9]{3}|20[1-3][0-9]|204[1-8]|any)$ + type: string + type: object + filter: + properties: + request_type: + enum: + - all + - illegal + - blocked + type: string + type: object + type: object + type: object + served: true + storage: true diff --git a/deployment/charts/nginx-ingress/crds/appprotect.f5.com_appolicies.yaml b/deployment/charts/nginx-ingress/crds/appprotect.f5.com_appolicies.yaml new file mode 100644 index 0000000..8c49441 --- /dev/null +++ b/deployment/charts/nginx-ingress/crds/appprotect.f5.com_appolicies.yaml @@ -0,0 +1,1903 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.10.0 + creationTimestamp: null + name: appolicies.appprotect.f5.com +spec: + group: appprotect.f5.com + names: + kind: APPolicy + listKind: APPolicyList + plural: appolicies + singular: appolicy + preserveUnknownFields: false + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: APPolicyConfig is the Schema for the APPolicyconfigs API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: APPolicySpec defines the desired state of APPolicy + properties: + modifications: + items: + properties: + action: + type: string + description: + type: string + entity: + properties: + name: + type: string + type: object + entityChanges: + properties: + type: + type: string + type: object + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + modificationsReference: + properties: + link: + pattern: ^http + type: string + type: object + policy: + description: Defines the App Protect policy + properties: + applicationLanguage: + enum: + - iso-8859-10 + - iso-8859-6 + - windows-1255 + - auto-detect + - koi8-r + - gb18030 + - iso-8859-8 + - windows-1250 + - iso-8859-9 + - windows-1252 + - iso-8859-16 + - gb2312 + - iso-8859-2 + - iso-8859-5 + - windows-1257 + - windows-1256 + - iso-8859-13 + - windows-874 + - windows-1253 + - iso-8859-3 + - euc-jp + - utf-8 + - gbk + - windows-1251 + - big5 + - iso-8859-1 + - shift_jis + - euc-kr + - iso-8859-4 + - iso-8859-7 + - iso-8859-15 + type: string + blocking-settings: + properties: + evasions: + items: + properties: + description: + enum: + - '%u decoding' + - Apache whitespace + - Bad unescape + - Bare byte decoding + - Directory traversals + - IIS backslashes + - IIS Unicode codepoints + - Multiple decoding + type: string + enabled: + type: boolean + maxDecodingPasses: + type: integer + type: object + type: array + http-protocols: + items: + properties: + description: + enum: + - Unescaped space in URL + - Unparsable request content + - Several Content-Length headers + - 'POST request with Content-Length: 0' + - Null in request + - No Host header in HTTP/1.1 request + - Multiple host headers + - Host header contains IP address + - High ASCII characters in headers + - Header name with no header value + - CRLF characters before request start + - Content length should be a positive number + - Chunked request with Content-Length header + - Check maximum number of parameters + - Check maximum number of headers + - Body in GET or HEAD requests + - Bad multipart/form-data request parsing + - Bad multipart parameters parsing + - Bad HTTP version + - Bad host header value + type: string + enabled: + type: boolean + maxHeaders: + type: integer + maxParams: + type: integer + type: object + type: array + violations: + items: + properties: + alarm: + type: boolean + block: + type: boolean + description: + type: string + name: + enum: + - VIOL_GRPC_FORMAT + - VIOL_GRPC_MALFORMED + - VIOL_GRPC_METHOD + - VIOL_PARAMETER_ARRAY_VALUE + - VIOL_PARAMETER_VALUE_REGEXP + - VIOL_CSRF + - VIOL_PARAMETER_VALUE_BASE64 + - VIOL_MANDATORY_HEADER + - VIOL_HEADER_REPEATED + - VIOL_ASM_COOKIE_MODIFIED + - VIOL_BLACKLISTED_IP + - VIOL_COOKIE_EXPIRED + - VIOL_COOKIE_LENGTH + - VIOL_COOKIE_MALFORMED + - VIOL_COOKIE_MODIFIED + - VIOL_DATA_GUARD + - VIOL_ENCODING + - VIOL_EVASION + - VIOL_FILETYPE + - VIOL_FILE_UPLOAD + - VIOL_FILE_UPLOAD_IN_BODY + - VIOL_HEADER_LENGTH + - VIOL_HEADER_METACHAR + - VIOL_HTTP_PROTOCOL + - VIOL_HTTP_RESPONSE_STATUS + - VIOL_JSON_FORMAT + - VIOL_JSON_MALFORMED + - VIOL_JSON_SCHEMA + - VIOL_MANDATORY_PARAMETER + - VIOL_MANDATORY_REQUEST_BODY + - VIOL_METHOD + - VIOL_PARAMETER + - VIOL_PARAMETER_DATA_TYPE + - VIOL_PARAMETER_EMPTY_VALUE + - VIOL_PARAMETER_LOCATION + - VIOL_PARAMETER_MULTIPART_NULL_VALUE + - VIOL_PARAMETER_NAME_METACHAR + - VIOL_PARAMETER_NUMERIC_VALUE + - VIOL_PARAMETER_REPEATED + - VIOL_PARAMETER_STATIC_VALUE + - VIOL_PARAMETER_VALUE_LENGTH + - VIOL_PARAMETER_VALUE_METACHAR + - VIOL_POST_DATA_LENGTH + - VIOL_QUERY_STRING_LENGTH + - VIOL_RATING_THREAT + - VIOL_RATING_NEED_EXAMINATION + - VIOL_REQUEST_MAX_LENGTH + - VIOL_REQUEST_LENGTH + - VIOL_THREAT_CAMPAIGN + - VIOL_URL + - VIOL_URL_CONTENT_TYPE + - VIOL_URL_LENGTH + - VIOL_URL_METACHAR + - VIOL_XML_FORMAT + - VIOL_XML_MALFORMED + type: string + type: object + type: array + type: object + blockingSettingReference: + properties: + link: + pattern: ^http + type: string + type: object + bot-defense: + properties: + mitigations: + properties: + anomalies: + items: + properties: + $action: + enum: + - delete + type: string + action: + enum: + - alarm + - block + - default + - detect + - ignore + type: string + name: + type: string + scoreThreshold: + pattern: '[0-9]|[1-9][0-9]|1[0-4][0-9]|150|default' + type: string + type: object + type: array + browsers: + items: + properties: + $action: + enum: + - delete + type: string + action: + enum: + - alarm + - block + - detect + type: string + browserDefinition: + properties: + $action: + enum: + - delete + type: string + isUserDefined: + type: boolean + matchRegex: + type: string + matchString: + type: string + name: + type: string + type: object + maxVersion: + maximum: 2147483647 + minimum: 0 + type: integer + minVersion: + maximum: 2147483647 + minimum: 0 + type: integer + name: + type: string + type: object + type: array + classes: + items: + properties: + action: + enum: + - alarm + - block + - detect + - ignore + type: string + name: + enum: + - browser + - malicious-bot + - suspicious-browser + - trusted-bot + - unknown + - untrusted-bot + type: string + type: object + type: array + signatures: + items: + properties: + $action: + enum: + - delete + type: string + action: + enum: + - alarm + - block + - detect + - ignore + type: string + name: + type: string + type: object + type: array + type: object + settings: + properties: + caseSensitiveHttpHeaders: + type: boolean + isEnabled: + type: boolean + type: object + type: object + browser-definitions: + items: + properties: + $action: + enum: + - delete + type: string + isUserDefined: + type: boolean + matchRegex: + type: string + matchString: + type: string + name: + type: string + type: object + type: array + caseInsensitive: + type: boolean + character-sets: + items: + properties: + characterSet: + items: + properties: + isAllowed: + type: boolean + metachar: + type: string + type: object + type: array + characterSetType: + enum: + - gwt-content + - header + - json-content + - parameter-name + - parameter-value + - plain-text-content + - url + - xml-content + type: string + type: object + type: array + characterSetReference: + properties: + link: + pattern: ^http + type: string + type: object + cookie-settings: + properties: + maximumCookieHeaderLength: + pattern: any|\d+ + type: string + type: object + cookieReference: + properties: + link: + pattern: ^http + type: string + type: object + cookieSettingsReference: + properties: + link: + pattern: ^http + type: string + type: object + cookies: + items: + properties: + $action: + enum: + - delete + type: string + accessibleOnlyThroughTheHttpProtocol: + type: boolean + attackSignaturesCheck: + type: boolean + decodeValueAsBase64: + enum: + - enabled + - disabled + - required + type: string + enforcementType: + type: string + insertSameSiteAttribute: + enum: + - lax + - none + - none-value + - strict + type: string + name: + type: string + securedOverHttpsConnection: + type: boolean + signatureOverrides: + items: + properties: + enabled: + type: boolean + name: + type: string + signatureId: + type: integer + tag: + type: string + type: object + type: array + type: + enum: + - explicit + - wildcard + type: string + wildcardOrder: + type: integer + type: object + type: array + csrf-protection: + properties: + enabled: + type: boolean + expirationTimeInSeconds: + pattern: disabled|\d+ + type: string + sslOnly: + type: boolean + type: object + csrf-urls: + items: + properties: + $action: + enum: + - delete + type: string + enforcementAction: + enum: + - verify-origin + - none + type: string + method: + enum: + - GET + - POST + - any + type: string + url: + type: string + wildcardOrder: + type: integer + type: object + type: array + data-guard: + properties: + creditCardNumbers: + type: boolean + enabled: + type: boolean + enforcementMode: + enum: + - ignore-urls-in-list + - enforce-urls-in-list + type: string + enforcementUrls: + items: + type: string + type: array + lastCcnDigitsToExpose: + type: integer + lastSsnDigitsToExpose: + type: integer + maskData: + type: boolean + usSocialSecurityNumbers: + type: boolean + type: object + dataGuardReference: + properties: + link: + pattern: ^http + type: string + type: object + description: + type: string + enablePassiveMode: + type: boolean + enforcementMode: + enum: + - transparent + - blocking + type: string + enforcer-settings: + properties: + enforcerStateCookies: + properties: + httpOnlyAttribute: + type: boolean + sameSiteAttribute: + enum: + - lax + - none + - none-value + - strict + type: string + secureAttribute: + enum: + - always + - never + type: string + type: object + type: object + filetypeReference: + properties: + link: + pattern: ^http + type: string + type: object + filetypes: + items: + properties: + $action: + enum: + - delete + type: string + allowed: + type: boolean + checkPostDataLength: + type: boolean + checkQueryStringLength: + type: boolean + checkRequestLength: + type: boolean + checkUrlLength: + type: boolean + name: + type: string + postDataLength: + type: integer + queryStringLength: + type: integer + requestLength: + type: integer + responseCheck: + type: boolean + type: + enum: + - explicit + - wildcard + type: string + urlLength: + type: integer + wildcardOrder: + type: integer + type: object + type: array + fullPath: + type: string + general: + properties: + allowedResponseCodes: + items: + format: int32 + maximum: 999 + minimum: 100 + type: integer + type: array + customXffHeaders: + items: + type: string + type: array + maskCreditCardNumbersInRequest: + type: boolean + trustXff: + type: boolean + type: object + generalReference: + properties: + link: + pattern: ^http + type: string + type: object + grpc-profiles: + items: + properties: + $action: + enum: + - delete + type: string + associateUrls: + type: boolean + attackSignaturesCheck: + type: boolean + defenseAttributes: + properties: + allowUnknownFields: + type: boolean + maximumDataLength: + pattern: any|\d+ + type: string + type: object + description: + type: string + hasIdlFiles: + type: boolean + idlFiles: + items: + properties: + idlFile: + properties: + contents: + type: string + fileName: + type: string + isBase64: + type: boolean + type: object + importUrl: + type: string + isPrimary: + type: boolean + primaryIdlFileName: + type: string + type: object + type: array + metacharElementCheck: + type: boolean + name: + type: string + signatureOverrides: + items: + properties: + enabled: + type: boolean + name: + type: string + signatureId: + type: integer + tag: + type: string + type: object + type: array + type: object + type: array + header-settings: + properties: + maximumHttpHeaderLength: + pattern: any|\d+ + type: string + type: object + headerReference: + properties: + link: + pattern: ^http + type: string + type: object + headerSettingsReference: + properties: + link: + pattern: ^http + type: string + type: object + headers: + items: + properties: + $action: + enum: + - delete + type: string + allowRepeatedOccurrences: + type: boolean + base64Decoding: + type: boolean + checkSignatures: + type: boolean + decodeValueAsBase64: + enum: + - enabled + - disabled + - required + type: string + htmlNormalization: + type: boolean + mandatory: + type: boolean + maskValueInLogs: + type: boolean + name: + type: string + normalizationViolations: + type: boolean + percentDecoding: + type: boolean + signatureOverrides: + items: + properties: + enabled: + type: boolean + name: + type: string + signatureId: + type: integer + tag: + type: string + type: object + type: array + type: + enum: + - explicit + - wildcard + type: string + urlNormalization: + type: boolean + wildcardOrder: + type: integer + type: object + type: array + host-names: + items: + properties: + $action: + enum: + - delete + type: string + includeSubdomains: + type: boolean + name: + type: string + type: object + type: array + idl-files: + items: + properties: + contents: + type: string + fileName: + type: string + isBase64: + type: boolean + type: object + type: array + json-profiles: + items: + properties: + $action: + enum: + - delete + type: string + attackSignaturesCheck: + type: boolean + defenseAttributes: + properties: + maximumArrayLength: + pattern: any|\d+ + type: string + maximumStructureDepth: + pattern: any|\d+ + type: string + maximumTotalLengthOfJSONData: + pattern: any|\d+ + type: string + maximumValueLength: + pattern: any|\d+ + type: string + tolerateJSONParsingWarnings: + type: boolean + type: object + description: + type: string + handleJsonValuesAsParameters: + type: boolean + hasValidationFiles: + type: boolean + metacharOverrides: + items: + properties: + isAllowed: + type: boolean + metachar: + type: string + type: object + type: array + name: + type: string + signatureOverrides: + items: + properties: + enabled: + type: boolean + name: + type: string + signatureId: + type: integer + tag: + type: string + type: object + type: array + validationFiles: + items: + properties: + importUrl: + type: string + isPrimary: + type: boolean + jsonValidationFile: + properties: + $action: + enum: + - delete + type: string + contents: + type: string + fileName: + type: string + isBase64: + type: boolean + type: object + type: object + type: array + type: object + type: array + json-validation-files: + items: + properties: + $action: + enum: + - delete + type: string + contents: + type: string + fileName: + type: string + isBase64: + type: boolean + type: object + type: array + jsonProfileReference: + properties: + link: + pattern: ^http + type: string + type: object + jsonValidationFileReference: + properties: + link: + pattern: ^http + type: string + type: object + methodReference: + properties: + link: + pattern: ^http + type: string + type: object + methods: + items: + properties: + $action: + enum: + - delete + type: string + name: + type: string + type: object + type: array + name: + type: string + open-api-files: + items: + properties: + link: + pattern: ^http + type: string + type: object + type: array + parameterReference: + properties: + link: + pattern: ^http + type: string + type: object + parameters: + items: + properties: + $action: + enum: + - delete + type: string + allowEmptyValue: + type: boolean + allowRepeatedParameterName: + type: boolean + arraySerializationFormat: + enum: + - csv + - form + - label + - matrix + - multi + - multipart + - pipe + - ssv + - tsv + type: string + attackSignaturesCheck: + type: boolean + checkMaxValue: + type: boolean + checkMaxValueLength: + type: boolean + checkMetachars: + type: boolean + checkMinValue: + type: boolean + checkMinValueLength: + type: boolean + checkMultipleOfValue: + type: boolean + contentProfile: + properties: + name: + type: string + type: object + dataType: + enum: + - alpha-numeric + - binary + - boolean + - decimal + - email + - integer + - none + - phone + type: string + decodeValueAsBase64: + enum: + - enabled + - disabled + - required + type: string + disallowFileUploadOfExecutables: + type: boolean + enableRegularExpression: + type: boolean + exclusiveMax: + type: boolean + exclusiveMin: + type: boolean + isBase64: + type: boolean + isCookie: + type: boolean + isHeader: + type: boolean + level: + enum: + - global + - url + type: string + mandatory: + type: boolean + maximumLength: + type: integer + maximumValue: + type: integer + metacharsOnParameterValueCheck: + type: boolean + minimumLength: + type: integer + minimumValue: + type: integer + multipleOf: + type: integer + name: + type: string + nameMetacharOverrides: + items: + properties: + isAllowed: + type: boolean + metachar: + type: string + type: object + type: array + objectSerializationStyle: + type: string + parameterEnumValues: + items: + type: string + type: array + parameterLocation: + enum: + - any + - cookie + - form-data + - header + - path + - query + type: string + regularExpression: + type: string + sensitiveParameter: + type: boolean + signatureOverrides: + items: + properties: + enabled: + type: boolean + name: + type: string + signatureId: + type: integer + tag: + type: string + type: object + type: array + staticValues: + type: string + type: + enum: + - explicit + - wildcard + type: string + url: + type: object + valueMetacharOverrides: + items: + properties: + isAllowed: + type: boolean + metachar: + type: string + type: object + type: array + valueType: + enum: + - array + - auto-detect + - dynamic-content + - dynamic-parameter-name + - ignore + - json + - object + - openapi-array + - static-content + - user-input + - xml + type: string + wildcardOrder: + type: integer + type: object + type: array + response-pages: + items: + properties: + ajaxActionType: + enum: + - alert-popup + - custom + - redirect + type: string + ajaxCustomContent: + type: string + ajaxEnabled: + type: boolean + ajaxPopupMessage: + type: string + ajaxRedirectUrl: + type: string + grpcStatusCode: + pattern: ABORTED|ALREADY_EXISTS|CANCELLED|DATA_LOSS|DEADLINE_EXCEEDED|FAILED_PRECONDITION|INTERNAL|INVALID_ARGUMENT|NOT_FOUND|OK|OUT_OF_RANGE|PERMISSION_DENIED|RESOURCE_EXHAUSTED|UNAUTHENTICATED|UNAVAILABLE|UNIMPLEMENTED|UNKNOWN|d+ + type: string + grpcStatusMessage: + type: string + responseActionType: + enum: + - custom + - default + - erase-cookies + - redirect + - soap-fault + type: string + responseContent: + type: string + responseHeader: + type: string + responsePageType: + enum: + - ajax + - ajax-login + - captcha + - captcha-fail + - default + - failed-login-honeypot + - failed-login-honeypot-ajax + - hijack + - leaked-credentials + - leaked-credentials-ajax + - mobile + - persistent-flow + - xml + - grpc + type: string + responseRedirectUrl: + type: string + type: object + type: array + responsePageReference: + properties: + link: + pattern: ^http + type: string + type: object + sensitive-parameters: + items: + properties: + $action: + enum: + - delete + type: string + name: + type: string + type: object + type: array + sensitiveParameterReference: + properties: + link: + pattern: ^http + type: string + type: object + server-technologies: + items: + properties: + $action: + enum: + - delete + type: string + serverTechnologyName: + enum: + - Jenkins + - SharePoint + - Oracle Application Server + - Python + - Oracle Identity Manager + - Spring Boot + - CouchDB + - SQLite + - Handlebars + - Mustache + - Prototype + - Zend + - Redis + - Underscore.js + - Ember.js + - ZURB Foundation + - ef.js + - Vue.js + - UIKit + - TYPO3 CMS + - RequireJS + - React + - MooTools + - Laravel + - GraphQL + - Google Web Toolkit + - Express.js + - CodeIgniter + - Backbone.js + - AngularJS + - JavaScript + - Nginx + - Jetty + - Joomla + - JavaServer Faces (JSF) + - Ruby + - MongoDB + - Django + - Node.js + - Citrix + - JBoss + - Elasticsearch + - Apache Struts + - XML + - PostgreSQL + - IBM DB2 + - Sybase/ASE + - CGI + - Proxy Servers + - SSI (Server Side Includes) + - Cisco + - Novell + - Macromedia JRun + - BEA Systems WebLogic Server + - Lotus Domino + - MySQL + - Oracle + - Microsoft SQL Server + - PHP + - Outlook Web Access + - Apache/NCSA HTTP Server + - Apache Tomcat + - WordPress + - Macromedia ColdFusion + - Unix/Linux + - Microsoft Windows + - ASP.NET + - Front Page Server Extensions (FPSE) + - IIS + - WebDAV + - ASP + - Java Servlets/JSP + - jQuery + type: string + type: object + type: array + serverTechnologyReference: + properties: + link: + pattern: ^http + type: string + type: object + signature-requirements: + items: + properties: + $action: + enum: + - delete + type: string + tag: + type: string + type: object + type: array + signature-sets: + items: + properties: + $action: + enum: + - delete + type: string + alarm: + type: boolean + block: + type: boolean + name: + type: string + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + signature-settings: + properties: + attackSignatureFalsePositiveMode: + enum: + - detect + - detect-and-allow + - disabled + type: string + minimumAccuracyForAutoAddedSignatures: + enum: + - high + - low + - medium + type: string + type: object + signatureReference: + properties: + link: + pattern: ^http + type: string + type: object + signatureSetReference: + properties: + link: + pattern: ^http + type: string + type: object + signatureSettingReference: + properties: + link: + pattern: ^http + type: string + type: object + signatures: + items: + properties: + enabled: + type: boolean + name: + type: string + signatureId: + type: integer + tag: + type: string + type: object + type: array + softwareVersion: + type: string + template: + properties: + name: + type: string + type: object + threat-campaigns: + items: + properties: + isEnabled: + type: boolean + name: + type: string + type: object + type: array + threatCampaignReference: + properties: + link: + pattern: ^http + type: string + type: object + urlReference: + properties: + link: + pattern: ^http + type: string + type: object + urls: + items: + properties: + $action: + enum: + - delete + type: string + allowRenderingInFrames: + enum: + - never + - only-same + type: string + allowRenderingInFramesOnlyFrom: + type: string + attackSignaturesCheck: + type: boolean + clickjackingProtection: + type: boolean + description: + type: string + disallowFileUploadOfExecutables: + type: boolean + html5CrossOriginRequestsEnforcement: + properties: + allowOriginsEnforcementMode: + enum: + - replace-with + - unmodified + type: string + checkAllowedMethods: + type: boolean + crossDomainAllowedOrigin: + items: + properties: + includeSubDomains: + type: boolean + originName: + type: string + originPort: + pattern: any|\d+ + type: string + originProtocol: + enum: + - http + - http/https + - https + type: string + type: object + type: array + enforcementMode: + enum: + - disabled + - enforce + type: string + type: object + isAllowed: + type: boolean + mandatoryBody: + type: boolean + metacharOverrides: + items: + properties: + isAllowed: + type: boolean + metachar: + type: string + type: object + type: array + metacharsOnUrlCheck: + type: boolean + method: + enum: + - ACL + - BCOPY + - BDELETE + - BMOVE + - BPROPFIND + - BPROPPATCH + - CHECKIN + - CHECKOUT + - CONNECT + - COPY + - DELETE + - GET + - HEAD + - LINK + - LOCK + - MERGE + - MKCOL + - MKWORKSPACE + - MOVE + - NOTIFY + - OPTIONS + - PATCH + - POLL + - POST + - PROPFIND + - PROPPATCH + - PUT + - REPORT + - RPC_IN_DATA + - RPC_OUT_DATA + - SEARCH + - SUBSCRIBE + - TRACE + - TRACK + - UNLINK + - UNLOCK + - UNSUBSCRIBE + - VERSION_CONTROL + - X-MS-ENUMATTS + - '*' + type: string + methodOverrides: + items: + properties: + allowed: + type: boolean + method: + enum: + - ACL + - BCOPY + - BDELETE + - BMOVE + - BPROPFIND + - BPROPPATCH + - CHECKIN + - CHECKOUT + - CONNECT + - COPY + - DELETE + - GET + - HEAD + - LINK + - LOCK + - MERGE + - MKCOL + - MKWORKSPACE + - MOVE + - NOTIFY + - OPTIONS + - PATCH + - POLL + - POST + - PROPFIND + - PROPPATCH + - PUT + - REPORT + - RPC_IN_DATA + - RPC_OUT_DATA + - SEARCH + - SUBSCRIBE + - TRACE + - TRACK + - UNLINK + - UNLOCK + - UNSUBSCRIBE + - VERSION_CONTROL + - X-MS-ENUMATTS + type: string + type: object + type: array + methodsOverrideOnUrlCheck: + type: boolean + name: + type: string + operationId: + type: string + positionalParameters: + items: + properties: + parameter: + properties: + $action: + enum: + - delete + type: string + allowEmptyValue: + type: boolean + allowRepeatedParameterName: + type: boolean + arraySerializationFormat: + enum: + - csv + - form + - label + - matrix + - multi + - multipart + - pipe + - ssv + - tsv + type: string + attackSignaturesCheck: + type: boolean + checkMaxValue: + type: boolean + checkMaxValueLength: + type: boolean + checkMetachars: + type: boolean + checkMinValue: + type: boolean + checkMinValueLength: + type: boolean + checkMultipleOfValue: + type: boolean + contentProfile: + properties: + name: + type: string + type: object + dataType: + enum: + - alpha-numeric + - binary + - boolean + - decimal + - email + - integer + - none + - phone + type: string + decodeValueAsBase64: + enum: + - enabled + - disabled + - required + type: string + disallowFileUploadOfExecutables: + type: boolean + enableRegularExpression: + type: boolean + exclusiveMax: + type: boolean + exclusiveMin: + type: boolean + isBase64: + type: boolean + isCookie: + type: boolean + isHeader: + type: boolean + level: + enum: + - global + - url + type: string + mandatory: + type: boolean + maximumLength: + type: integer + maximumValue: + type: integer + metacharsOnParameterValueCheck: + type: boolean + minimumLength: + type: integer + minimumValue: + type: integer + multipleOf: + type: integer + name: + type: string + nameMetacharOverrides: + items: + properties: + isAllowed: + type: boolean + metachar: + type: string + type: object + type: array + objectSerializationStyle: + type: string + parameterEnumValues: + items: + type: string + type: array + parameterLocation: + enum: + - any + - cookie + - form-data + - header + - path + - query + type: string + regularExpression: + type: string + sensitiveParameter: + type: boolean + signatureOverrides: + items: + properties: + enabled: + type: boolean + name: + type: string + signatureId: + type: integer + tag: + type: string + type: object + type: array + staticValues: + type: string + type: + enum: + - explicit + - wildcard + type: string + url: + type: object + valueMetacharOverrides: + items: + properties: + isAllowed: + type: boolean + metachar: + type: string + type: object + type: array + valueType: + enum: + - array + - auto-detect + - dynamic-content + - dynamic-parameter-name + - ignore + - json + - object + - openapi-array + - static-content + - user-input + - xml + type: string + wildcardOrder: + type: integer + type: object + urlSegmentIndex: + type: integer + type: object + type: array + protocol: + enum: + - http + - https + type: string + signatureOverrides: + items: + properties: + enabled: + type: boolean + name: + type: string + signatureId: + type: integer + tag: + type: string + type: object + type: array + type: + enum: + - explicit + - wildcard + type: string + urlContentProfiles: + items: + properties: + contentProfile: + properties: + name: + type: string + type: object + headerName: + type: string + headerOrder: + type: string + headerValue: + type: string + name: + type: string + type: + enum: + - apply-content-signatures + - apply-value-and-content-signatures + - disallow + - do-nothing + - form-data + - gwt + - json + - xml + - grpc + type: string + type: object + type: array + wildcardOrder: + type: integer + type: object + type: array + whitelist-ips: + items: + properties: + $action: + enum: + - delete + type: string + blockRequests: + enum: + - always + - never + - policy-default + type: string + ipAddress: + pattern: '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' + type: string + ipMask: + pattern: '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' + type: string + neverLogRequests: + type: boolean + type: object + type: array + whitelistIpReference: + properties: + link: + pattern: ^http + type: string + type: object + xml-profiles: + items: + properties: + $action: + enum: + - delete + type: string + attackSignaturesCheck: + type: boolean + defenseAttributes: + properties: + allowCDATA: + type: boolean + allowDTDs: + type: boolean + allowExternalReferences: + type: boolean + allowProcessingInstructions: + type: boolean + maximumAttributeValueLength: + pattern: any|\d+ + type: string + maximumAttributesPerElement: + pattern: any|\d+ + type: string + maximumChildrenPerElement: + pattern: any|\d+ + type: string + maximumDocumentDepth: + pattern: any|\d+ + type: string + maximumDocumentSize: + pattern: any|\d+ + type: string + maximumElements: + pattern: any|\d+ + type: string + maximumNSDeclarations: + pattern: any|\d+ + type: string + maximumNameLength: + pattern: any|\d+ + type: string + maximumNamespaceLength: + pattern: any|\d+ + type: string + tolerateCloseTagShorthand: + type: boolean + tolerateLeadingWhiteSpace: + type: boolean + tolerateNumericNames: + type: boolean + type: object + description: + type: string + enableWss: + type: boolean + followSchemaLinks: + type: boolean + name: + type: string + signatureOverrides: + items: + properties: + enabled: + type: boolean + name: + type: string + signatureId: + type: integer + tag: + type: string + type: object + type: array + type: object + type: array + xml-validation-files: + items: + properties: + $action: + enum: + - delete + type: string + contents: + type: string + fileName: + type: string + isBase64: + type: boolean + type: object + type: array + xmlProfileReference: + properties: + link: + pattern: ^http + type: string + type: object + xmlValidationFileReference: + properties: + link: + pattern: ^http + type: string + type: object + type: object + type: object + type: object + served: true + storage: true diff --git a/deployment/charts/nginx-ingress/crds/appprotect.f5.com_apusersigs.yaml b/deployment/charts/nginx-ingress/crds/appprotect.f5.com_apusersigs.yaml new file mode 100644 index 0000000..34eb078 --- /dev/null +++ b/deployment/charts/nginx-ingress/crds/appprotect.f5.com_apusersigs.yaml @@ -0,0 +1,93 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.10.0 + creationTimestamp: null + name: apusersigs.appprotect.f5.com +spec: + group: appprotect.f5.com + names: + kind: APUserSig + listKind: APUserSigList + plural: apusersigs + singular: apusersig + preserveUnknownFields: false + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: APUserSig is the Schema for the apusersigs API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: APUserSigSpec defines the desired state of APUserSig + properties: + properties: + type: string + signatures: + items: + properties: + accuracy: + enum: + - high + - medium + - low + type: string + attackType: + properties: + name: + type: string + type: object + description: + type: string + name: + type: string + references: + properties: + type: + enum: + - bugtraq + - cve + - nessus + - url + type: string + value: + type: string + type: object + risk: + enum: + - high + - medium + - low + type: string + rule: + type: string + signatureType: + enum: + - request + - response + type: string + systems: + items: + properties: + name: + type: string + type: object + type: array + type: object + type: array + tag: + type: string + type: object + type: object + served: true + storage: true diff --git a/deployment/charts/nginx-ingress/crds/appprotectdos.f5.com_apdoslogconfs.yaml b/deployment/charts/nginx-ingress/crds/appprotectdos.f5.com_apdoslogconfs.yaml new file mode 100644 index 0000000..e23e871 --- /dev/null +++ b/deployment/charts/nginx-ingress/crds/appprotectdos.f5.com_apdoslogconfs.yaml @@ -0,0 +1,68 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: apdoslogconfs.appprotectdos.f5.com +spec: + group: appprotectdos.f5.com + names: + kind: APDosLogConf + listKind: APDosLogConfList + plural: apdoslogconfs + singular: apdoslogconf + preserveUnknownFields: false + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: APDosLogConf is the Schema for the APDosLogConfs API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: APDosLogConfSpec defines the desired state of APDosLogConf + properties: + content: + properties: + format: + enum: + - splunk + - arcsight + - user-defined + type: string + format_string: + type: string + max_message_size: + pattern: ^([1-9]|[1-5][0-9]|6[0-4])k$ + type: string + type: object + filter: + properties: + traffic-mitigation-stats: + enum: + - none + - all + default: all + type: string + bad-actors: + pattern: ^(none|all|top ([1-9]|[1-9][0-9]|[1-9][0-9]{2,4}|100000))$ + default: top 10 + type: string + attack-signatures: + pattern: ^(none|all|top ([1-9]|[1-9][0-9]|[1-9][0-9]{2,4}|100000))$ + default: top 10 + type: string + type: object + type: object + type: object + served: true + storage: true diff --git a/deployment/charts/nginx-ingress/crds/appprotectdos.f5.com_apdospolicy.yaml b/deployment/charts/nginx-ingress/crds/appprotectdos.f5.com_apdospolicy.yaml new file mode 100644 index 0000000..a16399a --- /dev/null +++ b/deployment/charts/nginx-ingress/crds/appprotectdos.f5.com_apdospolicy.yaml @@ -0,0 +1,68 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: apdospolicies.appprotectdos.f5.com +spec: + group: appprotectdos.f5.com + names: + kind: APDosPolicy + listKind: APDosPoliciesList + plural: apdospolicies + singular: apdospolicy + preserveUnknownFields: false + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + type: object + description: APDosPolicy is the Schema for the APDosPolicy API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + type: object + description: APDosPolicySpec defines the desired state of APDosPolicy + properties: + mitigation_mode: + enum: + - "standard" + - "conservative" + - "none" + default: "standard" + type: string + signatures: + enum: + - "on" + - "off" + default: "on" + type: string + bad_actors: + enum: + - "on" + - "off" + default: "on" + type: string + automation_tools_detection: + enum: + - "on" + - "off" + default: "on" + type: string + tls_fingerprint: + enum: + - "on" + - "off" + default: "on" + type: string + served: true + storage: true diff --git a/deployment/charts/nginx-ingress/crds/appprotectdos.f5.com_dosprotectedresources.yaml b/deployment/charts/nginx-ingress/crds/appprotectdos.f5.com_dosprotectedresources.yaml new file mode 100644 index 0000000..66214fc --- /dev/null +++ b/deployment/charts/nginx-ingress/crds/appprotectdos.f5.com_dosprotectedresources.yaml @@ -0,0 +1,81 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: dosprotectedresources.appprotectdos.f5.com +spec: + group: appprotectdos.f5.com + names: + kind: DosProtectedResource + listKind: DosProtectedResourceList + plural: dosprotectedresources + shortNames: + - pr + singular: dosprotectedresource + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: DosProtectedResource defines a Dos protected resource. + type: object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: DosProtectedResourceSpec defines the properties and values a DosProtectedResource can have. + type: object + properties: + apDosMonitor: + description: 'ApDosMonitor is how NGINX App Protect DoS monitors the stress level of the protected object. The monitor requests are sent from localhost (127.0.0.1). Default value: URI - None, protocol - http1, timeout - NGINX App Protect DoS default.' + type: object + properties: + protocol: + description: Protocol determines if the server listens on http1 / http2 / grpc. The default is http1. + type: string + enum: + - http1 + - http2 + - grpc + timeout: + description: Timeout determines how long (in seconds) should NGINX App Protect DoS wait for a response. Default is 10 seconds for http1/http2 and 5 seconds for grpc. + type: integer + format: int64 + uri: + description: 'URI is the destination to the desired protected object in the nginx.conf:' + type: string + apDosPolicy: + description: ApDosPolicy is the namespace/name of a ApDosPolicy resource + type: string + dosAccessLogDest: + description: DosAccessLogDest is the network address for the access logs + type: string + dosSecurityLog: + description: DosSecurityLog defines the security log of the DosProtectedResource. + type: object + properties: + apDosLogConf: + description: ApDosLogConf is the namespace/name of a APDosLogConf resource + type: string + dosLogDest: + description: DosLogDest is the network address of a logging service, can be either IP or DNS name. + type: string + enable: + description: Enable enables the security logging feature if set to true + type: boolean + enable: + description: Enable enables the DOS feature if set to true + type: boolean + name: + description: Name is the name of protected object, max of 63 characters. + type: string + served: true + storage: true diff --git a/deployment/charts/nginx-ingress/crds/externaldns.nginx.org_dnsendpoints.yaml b/deployment/charts/nginx-ingress/crds/externaldns.nginx.org_dnsendpoints.yaml new file mode 100644 index 0000000..da9c648 --- /dev/null +++ b/deployment/charts/nginx-ingress/crds/externaldns.nginx.org_dnsendpoints.yaml @@ -0,0 +1,85 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: dnsendpoints.externaldns.nginx.org +spec: + group: externaldns.nginx.org + names: + kind: DNSEndpoint + listKind: DNSEndpointList + plural: dnsendpoints + singular: dnsendpoint + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: DNSEndpoint is the CRD wrapper for Endpoint + type: object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: DNSEndpointSpec holds information about endpoints. + type: object + properties: + endpoints: + type: array + items: + description: Endpoint describes DNS Endpoint. + type: object + properties: + dnsName: + description: The hostname for the DNS record + type: string + labels: + description: Labels stores labels defined for the Endpoint + type: object + additionalProperties: + type: string + providerSpecific: + description: ProviderSpecific stores provider specific config + type: array + items: + description: ProviderSpecificProperty represents provider specific config property. + type: object + properties: + name: + description: Name of the property + type: string + value: + description: Value of the property + type: string + recordTTL: + description: TTL for the record + type: integer + format: int64 + recordType: + description: RecordType type of record, e.g. CNAME, A, SRV, TXT, MX + type: string + targets: + description: The targets the DNS service points to + type: array + items: + type: string + status: + description: DNSEndpointStatus represents generation observed by the external dns controller. + type: object + properties: + observedGeneration: + description: The generation observed by by the external-dns controller. + type: integer + format: int64 + served: true + storage: true + subresources: + status: {} diff --git a/deployment/charts/nginx-ingress/crds/k8s.nginx.org_globalconfigurations.yaml b/deployment/charts/nginx-ingress/crds/k8s.nginx.org_globalconfigurations.yaml new file mode 100644 index 0000000..4a8bad7 --- /dev/null +++ b/deployment/charts/nginx-ingress/crds/k8s.nginx.org_globalconfigurations.yaml @@ -0,0 +1,50 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: globalconfigurations.k8s.nginx.org +spec: + group: k8s.nginx.org + names: + kind: GlobalConfiguration + listKind: GlobalConfigurationList + plural: globalconfigurations + shortNames: + - gc + singular: globalconfiguration + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: GlobalConfiguration defines the GlobalConfiguration resource. + type: object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: GlobalConfigurationSpec is the spec of the GlobalConfiguration resource. + type: object + properties: + listeners: + type: array + items: + description: Listener defines a listener. + type: object + properties: + name: + type: string + port: + type: integer + protocol: + type: string + served: true + storage: true diff --git a/deployment/charts/nginx-ingress/crds/k8s.nginx.org_policies.yaml b/deployment/charts/nginx-ingress/crds/k8s.nginx.org_policies.yaml new file mode 100644 index 0000000..b2cc6eb --- /dev/null +++ b/deployment/charts/nginx-ingress/crds/k8s.nginx.org_policies.yaml @@ -0,0 +1,294 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: policies.k8s.nginx.org +spec: + group: k8s.nginx.org + names: + kind: Policy + listKind: PolicyList + plural: policies + shortNames: + - pol + singular: policy + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Current state of the Policy. If the resource has a valid status, it means it has been validated and accepted by the Ingress Controller. + jsonPath: .status.state + name: State + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: Policy defines a Policy for VirtualServer and VirtualServerRoute resources. + type: object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PolicySpec is the spec of the Policy resource. The spec includes multiple fields, where each field represents a different policy. Only one policy (field) is allowed. + type: object + properties: + accessControl: + description: AccessControl defines an access policy based on the source IP of a request. + type: object + properties: + allow: + type: array + items: + type: string + deny: + type: array + items: + type: string + basicAuth: + description: 'BasicAuth holds HTTP Basic authentication configuration policy status: preview' + type: object + properties: + realm: + type: string + secret: + type: string + egressMTLS: + description: EgressMTLS defines an Egress MTLS policy. + type: object + properties: + ciphers: + type: string + protocols: + type: string + serverName: + type: boolean + sessionReuse: + type: boolean + sslName: + type: string + tlsSecret: + type: string + trustedCertSecret: + type: string + verifyDepth: + type: integer + verifyServer: + type: boolean + ingressClassName: + type: string + ingressMTLS: + description: IngressMTLS defines an Ingress MTLS policy. + type: object + properties: + clientCertSecret: + type: string + verifyClient: + type: string + verifyDepth: + type: integer + jwt: + description: JWTAuth holds JWT authentication configuration. + type: object + properties: + jwksURI: + type: string + keyCache: + type: string + realm: + type: string + secret: + type: string + token: + type: string + oidc: + description: OIDC defines an Open ID Connect policy. + type: object + properties: + authEndpoint: + type: string + clientID: + type: string + clientSecret: + type: string + jwksURI: + type: string + redirectURI: + type: string + scope: + type: string + tokenEndpoint: + type: string + zoneSyncLeeway: + type: integer + rateLimit: + description: RateLimit defines a rate limit policy. + type: object + properties: + burst: + type: integer + delay: + type: integer + dryRun: + type: boolean + key: + type: string + logLevel: + type: string + noDelay: + type: boolean + rate: + type: string + rejectCode: + type: integer + zoneSize: + type: string + waf: + description: WAF defines an WAF policy. + type: object + properties: + apPolicy: + type: string + enable: + type: boolean + securityLog: + description: SecurityLog defines the security log of a WAF policy. + type: object + properties: + apLogConf: + type: string + enable: + type: boolean + logDest: + type: string + securityLogs: + type: array + items: + description: SecurityLog defines the security log of a WAF policy. + type: object + properties: + apLogConf: + type: string + enable: + type: boolean + logDest: + type: string + status: + description: PolicyStatus is the status of the policy resource + type: object + properties: + message: + type: string + reason: + type: string + state: + type: string + served: true + storage: true + subresources: + status: {} + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Policy defines a Policy for VirtualServer and VirtualServerRoute resources. + type: object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PolicySpec is the spec of the Policy resource. The spec includes multiple fields, where each field represents a different policy. Only one policy (field) is allowed. + type: object + properties: + accessControl: + description: AccessControl defines an access policy based on the source IP of a request. + type: object + properties: + allow: + type: array + items: + type: string + deny: + type: array + items: + type: string + egressMTLS: + description: EgressMTLS defines an Egress MTLS policy. + type: object + properties: + ciphers: + type: string + protocols: + type: string + serverName: + type: boolean + sessionReuse: + type: boolean + sslName: + type: string + tlsSecret: + type: string + trustedCertSecret: + type: string + verifyDepth: + type: integer + verifyServer: + type: boolean + ingressMTLS: + description: IngressMTLS defines an Ingress MTLS policy. + type: object + properties: + clientCertSecret: + type: string + verifyClient: + type: string + verifyDepth: + type: integer + jwt: + description: JWTAuth holds JWT authentication configuration. + type: object + properties: + realm: + type: string + secret: + type: string + token: + type: string + rateLimit: + description: RateLimit defines a rate limit policy. + type: object + properties: + burst: + type: integer + delay: + type: integer + dryRun: + type: boolean + key: + type: string + logLevel: + type: string + noDelay: + type: boolean + rate: + type: string + rejectCode: + type: integer + zoneSize: + type: string + served: true + storage: false diff --git a/deployment/charts/nginx-ingress/crds/k8s.nginx.org_transportservers.yaml b/deployment/charts/nginx-ingress/crds/k8s.nginx.org_transportservers.yaml new file mode 100644 index 0000000..87ee09f --- /dev/null +++ b/deployment/charts/nginx-ingress/crds/k8s.nginx.org_transportservers.yaml @@ -0,0 +1,151 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: transportservers.k8s.nginx.org +spec: + group: k8s.nginx.org + names: + kind: TransportServer + listKind: TransportServerList + plural: transportservers + shortNames: + - ts + singular: transportserver + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Current state of the TransportServer. If the resource has a valid status, it means it has been validated and accepted by the Ingress Controller. + jsonPath: .status.state + name: State + type: string + - jsonPath: .status.reason + name: Reason + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: TransportServer defines the TransportServer resource. + type: object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TransportServerSpec is the spec of the TransportServer resource. + type: object + properties: + action: + description: Action defines an action. + type: object + properties: + pass: + type: string + host: + type: string + ingressClassName: + type: string + listener: + description: TransportServerListener defines a listener for a TransportServer. + type: object + properties: + name: + type: string + protocol: + type: string + serverSnippets: + type: string + sessionParameters: + description: SessionParameters defines session parameters. + type: object + properties: + timeout: + type: string + streamSnippets: + type: string + upstreamParameters: + description: UpstreamParameters defines parameters for an upstream. + type: object + properties: + connectTimeout: + type: string + nextUpstream: + type: boolean + nextUpstreamTimeout: + type: string + nextUpstreamTries: + type: integer + udpRequests: + type: integer + udpResponses: + type: integer + upstreams: + type: array + items: + description: Upstream defines an upstream. + type: object + properties: + failTimeout: + type: string + healthCheck: + description: HealthCheck defines the parameters for active Upstream HealthChecks. + type: object + properties: + enable: + type: boolean + fails: + type: integer + interval: + type: string + jitter: + type: string + match: + description: Match defines the parameters of a custom health check. + type: object + properties: + expect: + type: string + send: + type: string + passes: + type: integer + port: + type: integer + timeout: + type: string + loadBalancingMethod: + type: string + maxConns: + type: integer + maxFails: + type: integer + name: + type: string + port: + type: integer + service: + type: string + status: + description: TransportServerStatus defines the status for the TransportServer resource. + type: object + properties: + message: + type: string + reason: + type: string + state: + type: string + served: true + storage: true + subresources: + status: {} diff --git a/deployment/charts/nginx-ingress/crds/k8s.nginx.org_virtualserverroutes.yaml b/deployment/charts/nginx-ingress/crds/k8s.nginx.org_virtualserverroutes.yaml new file mode 100644 index 0000000..a8e897f --- /dev/null +++ b/deployment/charts/nginx-ingress/crds/k8s.nginx.org_virtualserverroutes.yaml @@ -0,0 +1,635 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: virtualserverroutes.k8s.nginx.org +spec: + group: k8s.nginx.org + names: + kind: VirtualServerRoute + listKind: VirtualServerRouteList + plural: virtualserverroutes + shortNames: + - vsr + singular: virtualserverroute + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Current state of the VirtualServerRoute. If the resource has a valid status, it means it has been validated and accepted by the Ingress Controller. + jsonPath: .status.state + name: State + type: string + - jsonPath: .spec.host + name: Host + type: string + - jsonPath: .status.externalEndpoints[*].ip + name: IP + type: string + - jsonPath: .status.externalEndpoints[*].hostname + name: ExternalHostname + priority: 1 + type: string + - jsonPath: .status.externalEndpoints[*].ports + name: Ports + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: VirtualServerRoute defines the VirtualServerRoute resource. + type: object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: VirtualServerRouteSpec is the spec of the VirtualServerRoute resource. + type: object + properties: + host: + type: string + ingressClassName: + type: string + subroutes: + type: array + items: + description: Route defines a route. + type: object + properties: + action: + description: Action defines an action. + type: object + properties: + pass: + type: string + proxy: + description: ActionProxy defines a proxy in an Action. + type: object + properties: + requestHeaders: + description: ProxyRequestHeaders defines the request headers manipulation in an ActionProxy. + type: object + properties: + pass: + type: boolean + set: + type: array + items: + description: Header defines an HTTP Header. + type: object + properties: + name: + type: string + value: + type: string + responseHeaders: + description: ProxyResponseHeaders defines the response headers manipulation in an ActionProxy. + type: object + properties: + add: + type: array + items: + description: AddHeader defines an HTTP Header with an optional Always field to use with the add_header NGINX directive. + type: object + properties: + always: + type: boolean + name: + type: string + value: + type: string + hide: + type: array + items: + type: string + ignore: + type: array + items: + type: string + pass: + type: array + items: + type: string + rewritePath: + type: string + upstream: + type: string + redirect: + description: ActionRedirect defines a redirect in an Action. + type: object + properties: + code: + type: integer + url: + type: string + return: + description: ActionReturn defines a return in an Action. + type: object + properties: + body: + type: string + code: + type: integer + type: + type: string + dos: + type: string + errorPages: + type: array + items: + description: ErrorPage defines an ErrorPage in a Route. + type: object + properties: + codes: + type: array + items: + type: integer + redirect: + description: ErrorPageRedirect defines a redirect for an ErrorPage. + type: object + properties: + code: + type: integer + url: + type: string + return: + description: ErrorPageReturn defines a return for an ErrorPage. + type: object + properties: + body: + type: string + code: + type: integer + headers: + type: array + items: + description: Header defines an HTTP Header. + type: object + properties: + name: + type: string + value: + type: string + type: + type: string + location-snippets: + type: string + matches: + type: array + items: + description: Match defines a match. + type: object + properties: + action: + description: Action defines an action. + type: object + properties: + pass: + type: string + proxy: + description: ActionProxy defines a proxy in an Action. + type: object + properties: + requestHeaders: + description: ProxyRequestHeaders defines the request headers manipulation in an ActionProxy. + type: object + properties: + pass: + type: boolean + set: + type: array + items: + description: Header defines an HTTP Header. + type: object + properties: + name: + type: string + value: + type: string + responseHeaders: + description: ProxyResponseHeaders defines the response headers manipulation in an ActionProxy. + type: object + properties: + add: + type: array + items: + description: AddHeader defines an HTTP Header with an optional Always field to use with the add_header NGINX directive. + type: object + properties: + always: + type: boolean + name: + type: string + value: + type: string + hide: + type: array + items: + type: string + ignore: + type: array + items: + type: string + pass: + type: array + items: + type: string + rewritePath: + type: string + upstream: + type: string + redirect: + description: ActionRedirect defines a redirect in an Action. + type: object + properties: + code: + type: integer + url: + type: string + return: + description: ActionReturn defines a return in an Action. + type: object + properties: + body: + type: string + code: + type: integer + type: + type: string + conditions: + type: array + items: + description: Condition defines a condition in a MatchRule. + type: object + properties: + argument: + type: string + cookie: + type: string + header: + type: string + value: + type: string + variable: + type: string + splits: + type: array + items: + description: Split defines a split. + type: object + properties: + action: + description: Action defines an action. + type: object + properties: + pass: + type: string + proxy: + description: ActionProxy defines a proxy in an Action. + type: object + properties: + requestHeaders: + description: ProxyRequestHeaders defines the request headers manipulation in an ActionProxy. + type: object + properties: + pass: + type: boolean + set: + type: array + items: + description: Header defines an HTTP Header. + type: object + properties: + name: + type: string + value: + type: string + responseHeaders: + description: ProxyResponseHeaders defines the response headers manipulation in an ActionProxy. + type: object + properties: + add: + type: array + items: + description: AddHeader defines an HTTP Header with an optional Always field to use with the add_header NGINX directive. + type: object + properties: + always: + type: boolean + name: + type: string + value: + type: string + hide: + type: array + items: + type: string + ignore: + type: array + items: + type: string + pass: + type: array + items: + type: string + rewritePath: + type: string + upstream: + type: string + redirect: + description: ActionRedirect defines a redirect in an Action. + type: object + properties: + code: + type: integer + url: + type: string + return: + description: ActionReturn defines a return in an Action. + type: object + properties: + body: + type: string + code: + type: integer + type: + type: string + weight: + type: integer + path: + type: string + policies: + type: array + items: + description: PolicyReference references a policy by name and an optional namespace. + type: object + properties: + name: + type: string + namespace: + type: string + route: + type: string + splits: + type: array + items: + description: Split defines a split. + type: object + properties: + action: + description: Action defines an action. + type: object + properties: + pass: + type: string + proxy: + description: ActionProxy defines a proxy in an Action. + type: object + properties: + requestHeaders: + description: ProxyRequestHeaders defines the request headers manipulation in an ActionProxy. + type: object + properties: + pass: + type: boolean + set: + type: array + items: + description: Header defines an HTTP Header. + type: object + properties: + name: + type: string + value: + type: string + responseHeaders: + description: ProxyResponseHeaders defines the response headers manipulation in an ActionProxy. + type: object + properties: + add: + type: array + items: + description: AddHeader defines an HTTP Header with an optional Always field to use with the add_header NGINX directive. + type: object + properties: + always: + type: boolean + name: + type: string + value: + type: string + hide: + type: array + items: + type: string + ignore: + type: array + items: + type: string + pass: + type: array + items: + type: string + rewritePath: + type: string + upstream: + type: string + redirect: + description: ActionRedirect defines a redirect in an Action. + type: object + properties: + code: + type: integer + url: + type: string + return: + description: ActionReturn defines a return in an Action. + type: object + properties: + body: + type: string + code: + type: integer + type: + type: string + weight: + type: integer + upstreams: + type: array + items: + description: Upstream defines an upstream. + type: object + properties: + buffer-size: + type: string + buffering: + type: boolean + buffers: + description: UpstreamBuffers defines Buffer Configuration for an Upstream. + type: object + properties: + number: + type: integer + size: + type: string + client-max-body-size: + type: string + connect-timeout: + type: string + fail-timeout: + type: string + healthCheck: + description: HealthCheck defines the parameters for active Upstream HealthChecks. + type: object + properties: + connect-timeout: + type: string + enable: + type: boolean + fails: + type: integer + grpcService: + type: string + grpcStatus: + type: integer + headers: + type: array + items: + description: Header defines an HTTP Header. + type: object + properties: + name: + type: string + value: + type: string + interval: + type: string + jitter: + type: string + mandatory: + type: boolean + passes: + type: integer + path: + type: string + persistent: + type: boolean + port: + type: integer + read-timeout: + type: string + send-timeout: + type: string + statusMatch: + type: string + tls: + description: UpstreamTLS defines a TLS configuration for an Upstream. + type: object + properties: + enable: + type: boolean + keepalive: + type: integer + lb-method: + type: string + max-conns: + type: integer + max-fails: + type: integer + name: + type: string + next-upstream: + type: string + next-upstream-timeout: + type: string + next-upstream-tries: + type: integer + ntlm: + type: boolean + port: + type: integer + queue: + description: UpstreamQueue defines Queue Configuration for an Upstream. + type: object + properties: + size: + type: integer + timeout: + type: string + read-timeout: + type: string + send-timeout: + type: string + service: + type: string + sessionCookie: + description: SessionCookie defines the parameters for session persistence. + type: object + properties: + domain: + type: string + enable: + type: boolean + expires: + type: string + httpOnly: + type: boolean + name: + type: string + path: + type: string + secure: + type: boolean + slow-start: + type: string + subselector: + type: object + additionalProperties: + type: string + tls: + description: UpstreamTLS defines a TLS configuration for an Upstream. + type: object + properties: + enable: + type: boolean + type: + type: string + use-cluster-ip: + type: boolean + status: + description: VirtualServerRouteStatus defines the status for the VirtualServerRoute resource. + type: object + properties: + externalEndpoints: + type: array + items: + description: ExternalEndpoint defines the IP/ Hostname and ports used to connect to this resource. + type: object + properties: + hostname: + type: string + ip: + type: string + ports: + type: string + message: + type: string + reason: + type: string + referencedBy: + type: string + state: + type: string + served: true + storage: true + subresources: + status: {} diff --git a/deployment/charts/nginx-ingress/crds/k8s.nginx.org_virtualservers.yaml b/deployment/charts/nginx-ingress/crds/k8s.nginx.org_virtualservers.yaml new file mode 100644 index 0000000..327dbfa --- /dev/null +++ b/deployment/charts/nginx-ingress/crds/k8s.nginx.org_virtualservers.yaml @@ -0,0 +1,715 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: virtualservers.k8s.nginx.org +spec: + group: k8s.nginx.org + names: + kind: VirtualServer + listKind: VirtualServerList + plural: virtualservers + shortNames: + - vs + singular: virtualserver + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Current state of the VirtualServer. If the resource has a valid status, it means it has been validated and accepted by the Ingress Controller. + jsonPath: .status.state + name: State + type: string + - jsonPath: .spec.host + name: Host + type: string + - jsonPath: .status.externalEndpoints[*].ip + name: IP + type: string + - jsonPath: .status.externalEndpoints[*].hostname + name: ExternalHostname + priority: 1 + type: string + - jsonPath: .status.externalEndpoints[*].ports + name: Ports + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: VirtualServer defines the VirtualServer resource. + type: object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: VirtualServerSpec is the spec of the VirtualServer resource. + type: object + properties: + dos: + type: string + externalDNS: + description: ExternalDNS defines externaldns sub-resource of a virtual server. + type: object + properties: + enable: + type: boolean + labels: + description: Labels stores labels defined for the Endpoint + type: object + additionalProperties: + type: string + providerSpecific: + description: ProviderSpecific stores provider specific config + type: array + items: + description: ProviderSpecificProperty defines specific property for using with ExternalDNS sub-resource. + type: object + properties: + name: + description: Name of the property + type: string + value: + description: Value of the property + type: string + recordTTL: + description: TTL for the record + type: integer + format: int64 + recordType: + type: string + host: + type: string + http-snippets: + type: string + ingressClassName: + type: string + policies: + type: array + items: + description: PolicyReference references a policy by name and an optional namespace. + type: object + properties: + name: + type: string + namespace: + type: string + routes: + type: array + items: + description: Route defines a route. + type: object + properties: + action: + description: Action defines an action. + type: object + properties: + pass: + type: string + proxy: + description: ActionProxy defines a proxy in an Action. + type: object + properties: + requestHeaders: + description: ProxyRequestHeaders defines the request headers manipulation in an ActionProxy. + type: object + properties: + pass: + type: boolean + set: + type: array + items: + description: Header defines an HTTP Header. + type: object + properties: + name: + type: string + value: + type: string + responseHeaders: + description: ProxyResponseHeaders defines the response headers manipulation in an ActionProxy. + type: object + properties: + add: + type: array + items: + description: AddHeader defines an HTTP Header with an optional Always field to use with the add_header NGINX directive. + type: object + properties: + always: + type: boolean + name: + type: string + value: + type: string + hide: + type: array + items: + type: string + ignore: + type: array + items: + type: string + pass: + type: array + items: + type: string + rewritePath: + type: string + upstream: + type: string + redirect: + description: ActionRedirect defines a redirect in an Action. + type: object + properties: + code: + type: integer + url: + type: string + return: + description: ActionReturn defines a return in an Action. + type: object + properties: + body: + type: string + code: + type: integer + type: + type: string + dos: + type: string + errorPages: + type: array + items: + description: ErrorPage defines an ErrorPage in a Route. + type: object + properties: + codes: + type: array + items: + type: integer + redirect: + description: ErrorPageRedirect defines a redirect for an ErrorPage. + type: object + properties: + code: + type: integer + url: + type: string + return: + description: ErrorPageReturn defines a return for an ErrorPage. + type: object + properties: + body: + type: string + code: + type: integer + headers: + type: array + items: + description: Header defines an HTTP Header. + type: object + properties: + name: + type: string + value: + type: string + type: + type: string + location-snippets: + type: string + matches: + type: array + items: + description: Match defines a match. + type: object + properties: + action: + description: Action defines an action. + type: object + properties: + pass: + type: string + proxy: + description: ActionProxy defines a proxy in an Action. + type: object + properties: + requestHeaders: + description: ProxyRequestHeaders defines the request headers manipulation in an ActionProxy. + type: object + properties: + pass: + type: boolean + set: + type: array + items: + description: Header defines an HTTP Header. + type: object + properties: + name: + type: string + value: + type: string + responseHeaders: + description: ProxyResponseHeaders defines the response headers manipulation in an ActionProxy. + type: object + properties: + add: + type: array + items: + description: AddHeader defines an HTTP Header with an optional Always field to use with the add_header NGINX directive. + type: object + properties: + always: + type: boolean + name: + type: string + value: + type: string + hide: + type: array + items: + type: string + ignore: + type: array + items: + type: string + pass: + type: array + items: + type: string + rewritePath: + type: string + upstream: + type: string + redirect: + description: ActionRedirect defines a redirect in an Action. + type: object + properties: + code: + type: integer + url: + type: string + return: + description: ActionReturn defines a return in an Action. + type: object + properties: + body: + type: string + code: + type: integer + type: + type: string + conditions: + type: array + items: + description: Condition defines a condition in a MatchRule. + type: object + properties: + argument: + type: string + cookie: + type: string + header: + type: string + value: + type: string + variable: + type: string + splits: + type: array + items: + description: Split defines a split. + type: object + properties: + action: + description: Action defines an action. + type: object + properties: + pass: + type: string + proxy: + description: ActionProxy defines a proxy in an Action. + type: object + properties: + requestHeaders: + description: ProxyRequestHeaders defines the request headers manipulation in an ActionProxy. + type: object + properties: + pass: + type: boolean + set: + type: array + items: + description: Header defines an HTTP Header. + type: object + properties: + name: + type: string + value: + type: string + responseHeaders: + description: ProxyResponseHeaders defines the response headers manipulation in an ActionProxy. + type: object + properties: + add: + type: array + items: + description: AddHeader defines an HTTP Header with an optional Always field to use with the add_header NGINX directive. + type: object + properties: + always: + type: boolean + name: + type: string + value: + type: string + hide: + type: array + items: + type: string + ignore: + type: array + items: + type: string + pass: + type: array + items: + type: string + rewritePath: + type: string + upstream: + type: string + redirect: + description: ActionRedirect defines a redirect in an Action. + type: object + properties: + code: + type: integer + url: + type: string + return: + description: ActionReturn defines a return in an Action. + type: object + properties: + body: + type: string + code: + type: integer + type: + type: string + weight: + type: integer + path: + type: string + policies: + type: array + items: + description: PolicyReference references a policy by name and an optional namespace. + type: object + properties: + name: + type: string + namespace: + type: string + route: + type: string + splits: + type: array + items: + description: Split defines a split. + type: object + properties: + action: + description: Action defines an action. + type: object + properties: + pass: + type: string + proxy: + description: ActionProxy defines a proxy in an Action. + type: object + properties: + requestHeaders: + description: ProxyRequestHeaders defines the request headers manipulation in an ActionProxy. + type: object + properties: + pass: + type: boolean + set: + type: array + items: + description: Header defines an HTTP Header. + type: object + properties: + name: + type: string + value: + type: string + responseHeaders: + description: ProxyResponseHeaders defines the response headers manipulation in an ActionProxy. + type: object + properties: + add: + type: array + items: + description: AddHeader defines an HTTP Header with an optional Always field to use with the add_header NGINX directive. + type: object + properties: + always: + type: boolean + name: + type: string + value: + type: string + hide: + type: array + items: + type: string + ignore: + type: array + items: + type: string + pass: + type: array + items: + type: string + rewritePath: + type: string + upstream: + type: string + redirect: + description: ActionRedirect defines a redirect in an Action. + type: object + properties: + code: + type: integer + url: + type: string + return: + description: ActionReturn defines a return in an Action. + type: object + properties: + body: + type: string + code: + type: integer + type: + type: string + weight: + type: integer + server-snippets: + type: string + tls: + description: TLS defines TLS configuration for a VirtualServer. + type: object + properties: + cert-manager: + description: CertManager defines a cert manager config for a TLS. + type: object + properties: + cluster-issuer: + type: string + common-name: + type: string + duration: + type: string + issuer: + type: string + issuer-group: + type: string + issuer-kind: + type: string + renew-before: + type: string + usages: + type: string + redirect: + description: TLSRedirect defines a redirect for a TLS. + type: object + properties: + basedOn: + type: string + code: + type: integer + enable: + type: boolean + secret: + type: string + upstreams: + type: array + items: + description: Upstream defines an upstream. + type: object + properties: + buffer-size: + type: string + buffering: + type: boolean + buffers: + description: UpstreamBuffers defines Buffer Configuration for an Upstream. + type: object + properties: + number: + type: integer + size: + type: string + client-max-body-size: + type: string + connect-timeout: + type: string + fail-timeout: + type: string + healthCheck: + description: HealthCheck defines the parameters for active Upstream HealthChecks. + type: object + properties: + connect-timeout: + type: string + enable: + type: boolean + fails: + type: integer + grpcService: + type: string + grpcStatus: + type: integer + headers: + type: array + items: + description: Header defines an HTTP Header. + type: object + properties: + name: + type: string + value: + type: string + interval: + type: string + jitter: + type: string + mandatory: + type: boolean + passes: + type: integer + path: + type: string + persistent: + type: boolean + port: + type: integer + read-timeout: + type: string + send-timeout: + type: string + statusMatch: + type: string + tls: + description: UpstreamTLS defines a TLS configuration for an Upstream. + type: object + properties: + enable: + type: boolean + keepalive: + type: integer + lb-method: + type: string + max-conns: + type: integer + max-fails: + type: integer + name: + type: string + next-upstream: + type: string + next-upstream-timeout: + type: string + next-upstream-tries: + type: integer + ntlm: + type: boolean + port: + type: integer + queue: + description: UpstreamQueue defines Queue Configuration for an Upstream. + type: object + properties: + size: + type: integer + timeout: + type: string + read-timeout: + type: string + send-timeout: + type: string + service: + type: string + sessionCookie: + description: SessionCookie defines the parameters for session persistence. + type: object + properties: + domain: + type: string + enable: + type: boolean + expires: + type: string + httpOnly: + type: boolean + name: + type: string + path: + type: string + secure: + type: boolean + slow-start: + type: string + subselector: + type: object + additionalProperties: + type: string + tls: + description: UpstreamTLS defines a TLS configuration for an Upstream. + type: object + properties: + enable: + type: boolean + type: + type: string + use-cluster-ip: + type: boolean + status: + description: VirtualServerStatus defines the status for the VirtualServer resource. + type: object + properties: + externalEndpoints: + type: array + items: + description: ExternalEndpoint defines the IP/ Hostname and ports used to connect to this resource. + type: object + properties: + hostname: + type: string + ip: + type: string + ports: + type: string + message: + type: string + reason: + type: string + state: + type: string + served: true + storage: true + subresources: + status: {} diff --git a/deployment/charts/nginx-ingress/templates/NOTES.txt b/deployment/charts/nginx-ingress/templates/NOTES.txt new file mode 100644 index 0000000..c5f4cdf --- /dev/null +++ b/deployment/charts/nginx-ingress/templates/NOTES.txt @@ -0,0 +1 @@ +The NGINX Ingress Controller has been installed. diff --git a/deployment/charts/nginx-ingress/templates/_helpers.tpl b/deployment/charts/nginx-ingress/templates/_helpers.tpl new file mode 100644 index 0000000..e04d1a3 --- /dev/null +++ b/deployment/charts/nginx-ingress/templates/_helpers.tpl @@ -0,0 +1,93 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Expand the name of the chart. +*/}} +{{- define "nginx-ingress.name" -}} +{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create labels +*/}} +{{- define "nginx-ingress.labels" -}} +app.kubernetes.io/name: {{ include "nginx-ingress.name" . }} +helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} + +{{/* +Expand the name of the configmap. +*/}} +{{- define "nginx-ingress.configName" -}} +{{- if .Values.controller.customConfigMap -}} +{{ .Values.controller.customConfigMap }} +{{- else -}} +{{- default (include "nginx-ingress.name" .) .Values.controller.config.name -}} +{{- end -}} +{{- end -}} + +{{/* +Expand leader election lock name. +*/}} +{{- define "nginx-ingress.leaderElectionName" -}} +{{- if .Values.controller.reportIngressStatus.leaderElectionLockName -}} +{{ .Values.controller.reportIngressStatus.leaderElectionLockName }} +{{- else -}} +{{- printf "%s-%s" (include "nginx-ingress.name" .) "leader-election" -}} +{{- end -}} +{{- end -}} + +{{/* +Expand service account name. +*/}} +{{- define "nginx-ingress.serviceAccountName" -}} +{{- default (include "nginx-ingress.name" .) .Values.controller.serviceAccount.name -}} +{{- end -}} + +{{/* +Expand service name. +*/}} +{{- define "nginx-ingress.serviceName" -}} +{{- default (include "nginx-ingress.name" .) .Values.controller.service.name }} +{{- end -}} + +{{/* +Expand serviceMonitor name. +*/}} +{{- define "nginx-ingress.serviceMonitorName" -}} +{{- default (include "nginx-ingress.name" .) .Values.controller.serviceMonitor.name }} +{{- end -}} + +{{/* +Expand default TLS name. +*/}} +{{- define "nginx-ingress.defaultTLSName" -}} +{{- printf "%s-%s" (include "nginx-ingress.name" .) "default-server-tls" -}} +{{- end -}} + +{{/* +Expand wildcard TLS name. +*/}} +{{- define "nginx-ingress.wildcardTLSName" -}} +{{- printf "%s-%s" (include "nginx-ingress.name" .) "wildcard-tls" -}} +{{- end -}} + +{{/* +Expand app name. +*/}} +{{- define "nginx-ingress.appName" -}} +{{- default (include "nginx-ingress.name" .) .Values.controller.name -}} +{{- end -}} + +{{/* +Expand image name. +*/}} +{{- define "nginx-ingress.image" -}} +{{- if .Values.controller.image.digest -}} +{{- printf "%s@%s" .Values.controller.image.repository .Values.controller.image.digest -}} +{{- else -}} +{{- printf "%s:%s" .Values.controller.image.repository .Values.controller.image.tag -}} +{{- end -}} +{{- end -}} diff --git a/deployment/charts/nginx-ingress/templates/controller-configmap.yaml b/deployment/charts/nginx-ingress/templates/controller-configmap.yaml new file mode 100644 index 0000000..fd11991 --- /dev/null +++ b/deployment/charts/nginx-ingress/templates/controller-configmap.yaml @@ -0,0 +1,17 @@ +{{- if not .Values.controller.customConfigMap -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "nginx-ingress.configName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "nginx-ingress.labels" . | nindent 4 }} +{{- if .Values.controller.config.annotations }} + annotations: +{{ toYaml .Values.controller.config.annotations | indent 4 }} +{{- end }} +data: +{{- if .Values.controller.config.entries }} +{{ toYaml .Values.controller.config.entries | indent 2 }} +{{- end }} +{{- end }} diff --git a/deployment/charts/nginx-ingress/templates/controller-daemonset.yaml b/deployment/charts/nginx-ingress/templates/controller-daemonset.yaml new file mode 100644 index 0000000..30a864d --- /dev/null +++ b/deployment/charts/nginx-ingress/templates/controller-daemonset.yaml @@ -0,0 +1,243 @@ +{{- if eq .Values.controller.kind "daemonset" }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ default (include "nginx-ingress.name" .) .Values.controller.name }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "nginx-ingress.labels" . | nindent 4 }} +{{- if .Values.controller.annotations }} + annotations: {{ toYaml .Values.controller.annotations | nindent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app: {{ include "nginx-ingress.appName" . }} + template: + metadata: + labels: + app: {{ include "nginx-ingress.appName" . }} +{{- if .Values.nginxServiceMesh.enable }} + nsm.nginx.com/daemonset: {{ default (include "nginx-ingress.name" .) .Values.controller.name }} + spiffe.io/spiffeid: "true" +{{- end }} +{{- if .Values.controller.pod.extraLabels }} +{{ toYaml .Values.controller.pod.extraLabels | indent 8 }} +{{- end }} +{{- if or .Values.prometheus.create (or .Values.controller.pod.annotations .Values.nginxServiceMesh.enable) }} + annotations: +{{- if .Values.prometheus.create }} + prometheus.io/scrape: "true" + prometheus.io/port: "{{ .Values.prometheus.port }}" + prometheus.io/scheme: "{{ .Values.prometheus.scheme }}" +{{- end }} +{{- if .Values.nginxServiceMesh.enable }} + nsm.nginx.com/enable-ingress: "true" + nsm.nginx.com/enable-egress: "{{ .Values.nginxServiceMesh.enableEgress }}" +{{- end }} +{{- if .Values.controller.pod.annotations }} +{{ toYaml .Values.controller.pod.annotations | indent 8 }} +{{- end }} +{{- end }} + spec: + serviceAccountName: {{ include "nginx-ingress.serviceAccountName" . }} + automountServiceAccountToken: true + terminationGracePeriodSeconds: {{ .Values.controller.terminationGracePeriodSeconds }} +{{- if .Values.controller.nodeSelector }} + nodeSelector: +{{ toYaml .Values.controller.nodeSelector | indent 8 }} +{{- end }} +{{- if .Values.controller.tolerations }} + tolerations: +{{ toYaml .Values.controller.tolerations | indent 6 }} +{{- end }} +{{- if .Values.controller.affinity }} + affinity: +{{ toYaml .Values.controller.affinity | indent 8 }} +{{- end }} +{{- if or .Values.controller.volumes .Values.nginxServiceMesh.enable }} + volumes: +{{- end }} +{{- if .Values.nginxServiceMesh.enable }} + - hostPath: + path: /run/spire/sockets + type: DirectoryOrCreate + name: spire-agent-socket +{{- end }} +{{- if .Values.controller.volumes }} +{{ toYaml .Values.controller.volumes | indent 6 }} +{{- end }} +{{- if .Values.controller.priorityClassName }} + priorityClassName: {{ .Values.controller.priorityClassName }} +{{- end }} + hostNetwork: {{ .Values.controller.hostNetwork }} + dnsPolicy: {{ .Values.controller.dnsPolicy }} + containers: + - name: {{ include "nginx-ingress.name" . }} + image: {{ include "nginx-ingress.image" . }} + imagePullPolicy: "{{ .Values.controller.image.pullPolicy }}" +{{- if .Values.controller.lifecycle }} + lifecycle: +{{ toYaml .Values.controller.lifecycle | indent 10 }} +{{- end }} + ports: + - name: http + containerPort: 80 + hostPort: 80 + - name: https + containerPort: 443 + hostPort: 443 +{{ if .Values.controller.customPorts }} +{{ toYaml .Values.controller.customPorts | indent 8 }} +{{ end }} +{{- if .Values.prometheus.create }} + - name: prometheus + containerPort: {{ .Values.prometheus.port }} +{{- end }} +{{- if .Values.serviceInsight.create }} + - name: service-insight + containerPort: {{ .Values.serviceInsight.port }} +{{- end }} +{{- if .Values.controller.readyStatus.enable }} + - name: readiness-port + containerPort: {{ .Values.controller.readyStatus.port }} + readinessProbe: + httpGet: + path: /nginx-ready + port: readiness-port + periodSeconds: 1 + initialDelaySeconds: {{ .Values.controller.readyStatus.initialDelaySeconds }} +{{- end }} + securityContext: + allowPrivilegeEscalation: true + runAsUser: 101 #nginx + runAsNonRoot: true + capabilities: + drop: + - ALL + add: + - NET_BIND_SERVICE +{{- if or .Values.controller.volumeMounts .Values.nginxServiceMesh.enable }} + volumeMounts: +{{- end }} +{{- if .Values.nginxServiceMesh.enable }} + - mountPath: /run/spire/sockets + name: spire-agent-socket +{{- end }} +{{- if .Values.controller.volumeMounts }} +{{ toYaml .Values.controller.volumeMounts | indent 8 }} +{{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name +{{- if .Values.nginxServiceMesh.enable }} + - name: POD_SERVICEACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName +{{- end }} + resources: +{{ toYaml .Values.controller.resources | indent 10 }} + args: + - -nginx-plus={{ .Values.controller.nginxplus }} + - -nginx-reload-timeout={{ .Values.controller.nginxReloadTimeout }} + - -enable-app-protect={{ .Values.controller.appprotect.enable }} +{{- if and .Values.controller.appprotect.enable .Values.controller.appprotect.logLevel }} + - -app-protect-log-level={{ .Values.controller.appprotect.logLevel }} +{{ end }} + - -enable-app-protect-dos={{ .Values.controller.appprotectdos.enable }} + {{- if .Values.controller.appprotectdos.enable }} + - -app-protect-dos-debug={{ .Values.controller.appprotectdos.debug }} + - -app-protect-dos-max-daemons={{ .Values.controller.appprotectdos.maxWorkers }} + - -app-protect-dos-max-workers={{ .Values.controller.appprotectdos.maxDaemons }} + - -app-protect-dos-memory={{ .Values.controller.appprotectdos.memory }} + {{ end }} + - -nginx-configmaps=$(POD_NAMESPACE)/{{ include "nginx-ingress.configName" . }} +{{- if .Values.controller.defaultTLS.secret }} + - -default-server-tls-secret={{ .Values.controller.defaultTLS.secret }} +{{ else if and (.Values.controller.defaultTLS.cert) (.Values.controller.defaultTLS.key) }} + - -default-server-tls-secret=$(POD_NAMESPACE)/{{ include "nginx-ingress.defaultTLSName" . }} +{{- end }} + - -ingress-class={{ .Values.controller.ingressClass }} +{{- if .Values.controller.watchNamespace }} + - -watch-namespace={{ .Values.controller.watchNamespace }} +{{- end }} +{{- if .Values.controller.watchNamespaceLabel }} + - -watch-namespace-label={{ .Values.controller.watchNamespaceLabel }} +{{- end }} +{{- if .Values.controller.watchSecretNamespace }} + - -watch-secret-namespace={{ .Values.controller.watchSecretNamespace }} +{{- end }} + - -health-status={{ .Values.controller.healthStatus }} + - -health-status-uri={{ .Values.controller.healthStatusURI }} + - -nginx-debug={{ .Values.controller.nginxDebug }} + - -v={{ .Values.controller.logLevel }} + - -nginx-status={{ .Values.controller.nginxStatus.enable }} +{{- if .Values.controller.nginxStatus.enable }} + - -nginx-status-port={{ .Values.controller.nginxStatus.port }} + - -nginx-status-allow-cidrs={{ .Values.controller.nginxStatus.allowCidrs }} +{{- end }} +{{- if .Values.controller.reportIngressStatus.enable }} + - -report-ingress-status +{{- if .Values.controller.reportIngressStatus.ingressLink }} + - -ingresslink={{ .Values.controller.reportIngressStatus.ingressLink }} +{{- else if .Values.controller.reportIngressStatus.externalService }} + - -external-service={{ .Values.controller.reportIngressStatus.externalService }} +{{- else if and (.Values.controller.service.create) (eq .Values.controller.service.type "LoadBalancer") }} + - -external-service={{ include "nginx-ingress.serviceName" . }} +{{- end }} + - -enable-leader-election={{ .Values.controller.reportIngressStatus.enableLeaderElection }} + - -leader-election-lock-name={{ include "nginx-ingress.leaderElectionName" . }} +{{- end }} +{{- if .Values.controller.wildcardTLS.secret }} + - -wildcard-tls-secret={{ .Values.controller.wildcardTLS.secret }} +{{- else if and .Values.controller.wildcardTLS.cert .Values.controller.wildcardTLS.key }} + - -wildcard-tls-secret=$(POD_NAMESPACE)/{{ include "nginx-ingress.wildcardTLSName" . }} +{{- end }} + - -enable-prometheus-metrics={{ .Values.prometheus.create }} + - -prometheus-metrics-listen-port={{ .Values.prometheus.port }} + - -prometheus-tls-secret={{ .Values.prometheus.secret }} + - -enable-service-insight={{ .Values.serviceInsight.create }} + - -service-insight-listen-port={{ .Values.serviceInsight.port }} + - -service-insight-tls-secret={{ .Values.serviceInsight.secret }} + - -enable-custom-resources={{ .Values.controller.enableCustomResources }} + - -enable-snippets={{ .Values.controller.enableSnippets }} + - -include-year={{ .Values.controller.includeYear }} + - -disable-ipv6={{ .Values.controller.disableIPV6 }} +{{- if .Values.controller.enableCustomResources }} + - -enable-tls-passthrough={{ .Values.controller.enableTLSPassthrough }} + - -enable-preview-policies={{ .Values.controller.enablePreviewPolicies }} + - -enable-cert-manager={{ .Values.controller.enableCertManager }} + - -enable-oidc={{ .Values.controller.enableOIDC }} + - -enable-external-dns={{ .Values.controller.enableExternalDNS }} +{{- if .Values.controller.globalConfiguration.create }} + - -global-configuration=$(POD_NAMESPACE)/{{ include "nginx-ingress.name" . }} +{{- end }} +{{- end }} + - -ready-status={{ .Values.controller.readyStatus.enable }} + - -ready-status-port={{ .Values.controller.readyStatus.port }} + - -enable-latency-metrics={{ .Values.controller.enableLatencyMetrics }} +{{- if .Values.nginxServiceMesh.enable }} + - -spire-agent-address=/run/spire/sockets/agent.sock + - -enable-internal-routes={{ .Values.nginxServiceMesh.enableEgress }} +{{- end }} +{{- if .Values.controller.extraContainers }} + {{ toYaml .Values.controller.extraContainers | nindent 6 }} +{{- end }} +{{- if .Values.controller.initContainers }} + initContainers: {{ toYaml .Values.controller.initContainers | nindent 8 }} +{{- end }} +{{- if .Values.controller.strategy }} + updateStrategy: +{{ toYaml .Values.controller.strategy | indent 4 }} +{{- end }} +{{- if .Values.controller.minReadySeconds }} + minReadySeconds: {{ .Values.controller.minReadySeconds }} +{{- end }} +{{- end }} diff --git a/deployment/charts/nginx-ingress/templates/controller-deployment.yaml b/deployment/charts/nginx-ingress/templates/controller-deployment.yaml new file mode 100644 index 0000000..282e255 --- /dev/null +++ b/deployment/charts/nginx-ingress/templates/controller-deployment.yaml @@ -0,0 +1,246 @@ +{{- if eq .Values.controller.kind "deployment" }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ default (include "nginx-ingress.name" .) .Values.controller.name }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "nginx-ingress.labels" . | nindent 4 }} +{{- if .Values.controller.annotations }} + annotations: {{ toYaml .Values.controller.annotations | nindent 4 }} +{{- end }} +spec: + replicas: {{ .Values.controller.replicaCount }} + selector: + matchLabels: + app: {{ include "nginx-ingress.appName" . }} + template: + metadata: + labels: + app: {{ include "nginx-ingress.appName" . }} +{{- if .Values.nginxServiceMesh.enable }} + nsm.nginx.com/deployment: {{ default (include "nginx-ingress.name" .) .Values.controller.name }} + spiffe.io/spiffeid: "true" +{{- end }} +{{- if .Values.controller.pod.extraLabels }} +{{ toYaml .Values.controller.pod.extraLabels | indent 8 }} +{{- end }} +{{- if or .Values.prometheus.create (or .Values.controller.pod.annotations .Values.nginxServiceMesh.enable) }} + annotations: +{{- if .Values.prometheus.create }} + prometheus.io/scrape: "true" + prometheus.io/port: "{{ .Values.prometheus.port }}" + prometheus.io/scheme: "{{ .Values.prometheus.scheme }}" +{{- end }} +{{- if .Values.nginxServiceMesh.enable }} + nsm.nginx.com/enable-ingress: "true" + nsm.nginx.com/enable-egress: "{{ .Values.nginxServiceMesh.enableEgress }}" +{{- end }} +{{- if .Values.controller.pod.annotations }} +{{ toYaml .Values.controller.pod.annotations | indent 8 }} +{{- end }} +{{- end }} + spec: +{{- if .Values.controller.nodeSelector }} + nodeSelector: +{{ toYaml .Values.controller.nodeSelector | indent 8 }} +{{- end }} +{{- if .Values.controller.tolerations }} + tolerations: +{{ toYaml .Values.controller.tolerations | indent 6 }} +{{- end }} +{{- if .Values.controller.affinity }} + affinity: +{{ toYaml .Values.controller.affinity | indent 8 }} +{{- end }} +{{- if .Values.controller.topologySpreadConstraints }} + topologySpreadConstraints: +{{ toYaml .Values.controller.topologySpreadConstraints | indent 8 }} +{{- end }} +{{- if or (.Values.controller.volumes) (.Values.nginxServiceMesh.enable) }} + volumes: +{{- end }} +{{- if .Values.nginxServiceMesh.enable }} + - hostPath: + path: /run/spire/sockets + type: DirectoryOrCreate + name: spire-agent-socket +{{- end }} +{{- if .Values.controller.volumes }} +{{ toYaml .Values.controller.volumes | indent 6 }} +{{- end }} +{{- if .Values.controller.priorityClassName }} + priorityClassName: {{ .Values.controller.priorityClassName }} +{{- end }} + serviceAccountName: {{ include "nginx-ingress.serviceAccountName" . }} + automountServiceAccountToken: true + terminationGracePeriodSeconds: {{ .Values.controller.terminationGracePeriodSeconds }} + hostNetwork: {{ .Values.controller.hostNetwork }} + dnsPolicy: {{ .Values.controller.dnsPolicy }} + containers: + - image: {{ include "nginx-ingress.image" . }} + name: {{ include "nginx-ingress.name" . }} + imagePullPolicy: "{{ .Values.controller.image.pullPolicy }}" +{{- if .Values.controller.lifecycle }} + lifecycle: +{{ toYaml .Values.controller.lifecycle | indent 10 }} +{{- end }} + ports: + - name: http + containerPort: 80 + - name: https + containerPort: 443 +{{ if .Values.controller.customPorts }} +{{ toYaml .Values.controller.customPorts | indent 8 }} +{{ end }} +{{- if .Values.prometheus.create }} + - name: prometheus + containerPort: {{ .Values.prometheus.port }} +{{- end }} +{{- if .Values.serviceInsight.create }} + - name: service-insight + containerPort: {{ .Values.serviceInsight.port }} +{{- end }} +{{- if .Values.controller.readyStatus.enable }} + - name: readiness-port + containerPort: {{ .Values.controller.readyStatus.port }} + readinessProbe: + httpGet: + path: /nginx-ready + port: readiness-port + periodSeconds: 1 + initialDelaySeconds: {{ .Values.controller.readyStatus.initialDelaySeconds }} +{{- end }} + resources: +{{ toYaml .Values.controller.resources | indent 10 }} + securityContext: + allowPrivilegeEscalation: true + runAsUser: 101 #nginx + runAsNonRoot: true + capabilities: + drop: + - ALL + add: + - NET_BIND_SERVICE +{{- if or (.Values.controller.volumeMounts) (.Values.nginxServiceMesh.enable) }} + volumeMounts: +{{- end }} +{{- if .Values.nginxServiceMesh.enable }} + - mountPath: /run/spire/sockets + name: spire-agent-socket +{{- end }} +{{- if .Values.controller.volumeMounts}} +{{ toYaml .Values.controller.volumeMounts | indent 8 }} +{{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name +{{- if .Values.nginxServiceMesh.enable }} + - name: POD_SERVICEACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName +{{- end }} + args: + - -nginx-plus={{ .Values.controller.nginxplus }} + - -nginx-reload-timeout={{ .Values.controller.nginxReloadTimeout }} + - -enable-app-protect={{ .Values.controller.appprotect.enable }} +{{- if and .Values.controller.appprotect.enable .Values.controller.appprotect.logLevel }} + - -app-protect-log-level={{ .Values.controller.appprotect.logLevel }} +{{ end }} + - -enable-app-protect-dos={{ .Values.controller.appprotectdos.enable }} +{{- if .Values.controller.appprotectdos.enable }} + - -app-protect-dos-debug={{ .Values.controller.appprotectdos.debug }} + - -app-protect-dos-max-daemons={{ .Values.controller.appprotectdos.maxWorkers }} + - -app-protect-dos-max-workers={{ .Values.controller.appprotectdos.maxDaemons }} + - -app-protect-dos-memory={{ .Values.controller.appprotectdos.memory }} +{{ end }} + - -nginx-configmaps=$(POD_NAMESPACE)/{{ include "nginx-ingress.configName" . }} +{{- if .Values.controller.defaultTLS.secret }} + - -default-server-tls-secret={{ .Values.controller.defaultTLS.secret }} +{{ else if and (.Values.controller.defaultTLS.cert) (.Values.controller.defaultTLS.key) }} + - -default-server-tls-secret=$(POD_NAMESPACE)/{{ include "nginx-ingress.defaultTLSName" . }} +{{- end }} + - -ingress-class={{ .Values.controller.ingressClass }} +{{- if .Values.controller.watchNamespace }} + - -watch-namespace={{ .Values.controller.watchNamespace }} +{{- end }} +{{- if .Values.controller.watchNamespaceLabel }} + - -watch-namespace-label={{ .Values.controller.watchNamespaceLabel }} +{{- end }} +{{- if .Values.controller.watchSecretNamespace }} + - -watch-secret-namespace={{ .Values.controller.watchSecretNamespace }} +{{- end }} + - -health-status={{ .Values.controller.healthStatus }} + - -health-status-uri={{ .Values.controller.healthStatusURI }} + - -nginx-debug={{ .Values.controller.nginxDebug }} + - -v={{ .Values.controller.logLevel }} + - -nginx-status={{ .Values.controller.nginxStatus.enable }} +{{- if .Values.controller.nginxStatus.enable }} + - -nginx-status-port={{ .Values.controller.nginxStatus.port }} + - -nginx-status-allow-cidrs={{ .Values.controller.nginxStatus.allowCidrs }} +{{- end }} +{{- if .Values.controller.reportIngressStatus.enable }} + - -report-ingress-status +{{- if .Values.controller.reportIngressStatus.ingressLink }} + - -ingresslink={{ .Values.controller.reportIngressStatus.ingressLink }} +{{- else if .Values.controller.reportIngressStatus.externalService }} + - -external-service={{ .Values.controller.reportIngressStatus.externalService }} +{{- else if and (.Values.controller.service.create) (eq .Values.controller.service.type "LoadBalancer") }} + - -external-service={{ include "nginx-ingress.serviceName" . }} +{{- end }} + - -enable-leader-election={{ .Values.controller.reportIngressStatus.enableLeaderElection }} + - -leader-election-lock-name={{ include "nginx-ingress.leaderElectionName" . }} +{{- end }} +{{- if .Values.controller.wildcardTLS.secret }} + - -wildcard-tls-secret={{ .Values.controller.wildcardTLS.secret }} +{{- else if and .Values.controller.wildcardTLS.cert .Values.controller.wildcardTLS.key }} + - -wildcard-tls-secret=$(POD_NAMESPACE)/{{ include "nginx-ingress.wildcardTLSName" . }} +{{- end }} + - -enable-prometheus-metrics={{ .Values.prometheus.create }} + - -prometheus-metrics-listen-port={{ .Values.prometheus.port }} + - -prometheus-tls-secret={{ .Values.prometheus.secret }} + - -enable-service-insight={{ .Values.serviceInsight.create }} + - -service-insight-listen-port={{ .Values.serviceInsight.port }} + - -service-insight-tls-secret={{ .Values.serviceInsight.secret }} + - -enable-custom-resources={{ .Values.controller.enableCustomResources }} + - -enable-snippets={{ .Values.controller.enableSnippets }} + - -include-year={{ .Values.controller.includeYear }} + - -disable-ipv6={{ .Values.controller.disableIPV6 }} +{{- if .Values.controller.enableCustomResources }} + - -enable-tls-passthrough={{ .Values.controller.enableTLSPassthrough }} + - -enable-preview-policies={{ .Values.controller.enablePreviewPolicies }} + - -enable-cert-manager={{ .Values.controller.enableCertManager }} + - -enable-oidc={{ .Values.controller.enableOIDC }} + - -enable-external-dns={{ .Values.controller.enableExternalDNS }} +{{- if .Values.controller.globalConfiguration.create }} + - -global-configuration=$(POD_NAMESPACE)/{{ include "nginx-ingress.name" . }} +{{- end }} +{{- end }} + - -ready-status={{ .Values.controller.readyStatus.enable }} + - -ready-status-port={{ .Values.controller.readyStatus.port }} + - -enable-latency-metrics={{ .Values.controller.enableLatencyMetrics }} +{{- if .Values.nginxServiceMesh.enable }} + - -spire-agent-address=/run/spire/sockets/agent.sock + - -enable-internal-routes={{ .Values.nginxServiceMesh.enableEgress }} +{{- end }} +{{- if .Values.controller.extraContainers }} + {{ toYaml .Values.controller.extraContainers | nindent 6 }} +{{- end }} +{{- if .Values.controller.initContainers }} + initContainers: {{ toYaml .Values.controller.initContainers | nindent 8 }} +{{- end }} +{{- if .Values.controller.strategy }} + strategy: +{{ toYaml .Values.controller.strategy | indent 4 }} +{{- end }} +{{- if .Values.controller.minReadySeconds }} + minReadySeconds: {{ .Values.controller.minReadySeconds }} +{{- end }} +{{- end }} diff --git a/deployment/charts/nginx-ingress/templates/controller-globalconfiguration.yaml b/deployment/charts/nginx-ingress/templates/controller-globalconfiguration.yaml new file mode 100644 index 0000000..b0bba48 --- /dev/null +++ b/deployment/charts/nginx-ingress/templates/controller-globalconfiguration.yaml @@ -0,0 +1,11 @@ +{{ if .Values.controller.globalConfiguration.create }} +apiVersion: k8s.nginx.org/v1alpha1 +kind: GlobalConfiguration +metadata: + name: {{ include "nginx-ingress.name" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "nginx-ingress.labels" . | nindent 4 }} +spec: +{{ toYaml .Values.controller.globalConfiguration.spec | indent 2 }} +{{- end }} diff --git a/deployment/charts/nginx-ingress/templates/controller-hpa.yaml b/deployment/charts/nginx-ingress/templates/controller-hpa.yaml new file mode 100644 index 0000000..1d705f1 --- /dev/null +++ b/deployment/charts/nginx-ingress/templates/controller-hpa.yaml @@ -0,0 +1,37 @@ +{{- if and .Values.controller.autoscaling.enabled (eq .Values.controller.kind "deployment") (semverCompare ">=1.23.0" .Capabilities.KubeVersion.Version) -}} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "nginx-ingress.serviceName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "nginx-ingress.labels" . | nindent 4 }} +{{- if .Values.controller.autoscaling.annotations }} + annotations: +{{ toYaml .Values.controller.autoscaling.annotations | indent 4 }} +{{- end }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ default (include "nginx-ingress.name" .) .Values.controller.name }} + minReplicas: {{ .Values.controller.autoscaling.minReplicas }} + maxReplicas: {{ .Values.controller.autoscaling.maxReplicas }} + metrics: + {{- if .Values.controller.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.controller.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.controller.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.controller.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/deployment/charts/nginx-ingress/templates/controller-ingress-class.yaml b/deployment/charts/nginx-ingress/templates/controller-ingress-class.yaml new file mode 100644 index 0000000..bc071b4 --- /dev/null +++ b/deployment/charts/nginx-ingress/templates/controller-ingress-class.yaml @@ -0,0 +1,10 @@ +apiVersion: networking.k8s.io/v1 +kind: IngressClass +metadata: + name: {{ .Values.controller.ingressClass }} +{{- if .Values.controller.setAsDefaultIngress }} + annotations: + ingressclass.kubernetes.io/is-default-class: "true" +{{- end }} +spec: + controller: nginx.org/ingress-controller diff --git a/deployment/charts/nginx-ingress/templates/controller-leader-election-configmap.yaml b/deployment/charts/nginx-ingress/templates/controller-leader-election-configmap.yaml new file mode 100644 index 0000000..ef6f79a --- /dev/null +++ b/deployment/charts/nginx-ingress/templates/controller-leader-election-configmap.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "nginx-ingress.leaderElectionName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "nginx-ingress.labels" . | nindent 4 }} +{{- if .Values.controller.reportIngressStatus.annotations }} + annotations: +{{ toYaml .Values.controller.reportIngressStatus.annotations | indent 4 }} +{{- end }} diff --git a/deployment/charts/nginx-ingress/templates/controller-secret.yaml b/deployment/charts/nginx-ingress/templates/controller-secret.yaml new file mode 100644 index 0000000..f9941e8 --- /dev/null +++ b/deployment/charts/nginx-ingress/templates/controller-secret.yaml @@ -0,0 +1,13 @@ +{{ if and (not .Values.controller.defaultTLS.secret) (.Values.controller.defaultTLS.cert) (.Values.controller.defaultTLS.key) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "nginx-ingress.defaultTLSName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "nginx-ingress.labels" . | nindent 4 }} +type: kubernetes.io/tls +data: + tls.crt: {{ .Values.controller.defaultTLS.cert }} + tls.key: {{ .Values.controller.defaultTLS.key }} +{{- end }} diff --git a/deployment/charts/nginx-ingress/templates/controller-service.yaml b/deployment/charts/nginx-ingress/templates/controller-service.yaml new file mode 100644 index 0000000..9a125cd --- /dev/null +++ b/deployment/charts/nginx-ingress/templates/controller-service.yaml @@ -0,0 +1,69 @@ +{{- if .Values.controller.service.create }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "nginx-ingress.serviceName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "nginx-ingress.labels" . | nindent 4 }} +{{- if .Values.controller.service.extraLabels }} +{{ toYaml .Values.controller.service.extraLabels | indent 4 }} +{{- end }} +{{- if .Values.controller.service.annotations }} + annotations: +{{ toYaml .Values.controller.service.annotations | indent 4 }} +{{- end }} +spec: +{{- if or (eq .Values.controller.service.type "LoadBalancer") (eq .Values.controller.service.type "NodePort") }} + {{- if .Values.controller.service.externalTrafficPolicy }} + externalTrafficPolicy: {{ .Values.controller.service.externalTrafficPolicy }} + {{- end }} +{{- end }} +{{- if eq .Values.controller.service.type "LoadBalancer" }} + {{- if and (semverCompare ">=1.22.0-0" .Capabilities.KubeVersion.Version) (.Values.controller.service.allocateLoadBalancerNodePorts) }} + allocateLoadBalancerNodePorts: {{ .Values.controller.service.allocateLoadBalancerNodePorts }} + {{- end }} + {{- if .Values.controller.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.controller.service.loadBalancerIP }} + {{- end }} + {{- if .Values.controller.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{ toYaml .Values.controller.service.loadBalancerSourceRanges | indent 4 }} + {{- end }} +{{- end }} + type: {{ .Values.controller.service.type }} + {{- if .Values.controller.service.ipFamilyPolicy }} + ipFamilyPolicy: {{ .Values.controller.service.ipFamilyPolicy }} + {{- end }} + {{- if .Values.controller.service.ipFamilies }} + ipFamilies: {{ .Values.controller.service.ipFamilies }} + {{- end }} + ports: +{{- if .Values.controller.service.customPorts }} +{{ toYaml .Values.controller.service.customPorts | indent 2 }} +{{ end }} +{{- if .Values.controller.service.httpPort.enable }} + - port: {{ .Values.controller.service.httpPort.port }} + targetPort: {{ .Values.controller.service.httpPort.targetPort }} + protocol: TCP + name: http + {{- if eq .Values.controller.service.type "NodePort" }} + nodePort: {{ .Values.controller.service.httpPort.nodePort }} + {{- end }} +{{- end }} +{{- if .Values.controller.service.httpsPort.enable }} + - port: {{ .Values.controller.service.httpsPort.port }} + targetPort: {{ .Values.controller.service.httpsPort.targetPort }} + protocol: TCP + name: https + {{- if eq .Values.controller.service.type "NodePort" }} + nodePort: {{ .Values.controller.service.httpsPort.nodePort }} + {{- end }} +{{- end }} + selector: + app: {{ include "nginx-ingress.appName" . }} + {{- if .Values.controller.service.externalIPs }} + externalIPs: +{{ toYaml .Values.controller.service.externalIPs | indent 4 }} + {{- end }} +{{- end }} diff --git a/deployment/charts/nginx-ingress/templates/controller-serviceaccount.yaml b/deployment/charts/nginx-ingress/templates/controller-serviceaccount.yaml new file mode 100644 index 0000000..e1a3b51 --- /dev/null +++ b/deployment/charts/nginx-ingress/templates/controller-serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.rbac.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: +{{- if .Values.controller.serviceAccount.annotations }} + annotations: {{- toYaml .Values.controller.serviceAccount.annotations | nindent 4 }} +{{- end }} + name: {{ include "nginx-ingress.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "nginx-ingress.labels" . | nindent 4 }} +{{- if .Values.controller.serviceAccount.imagePullSecretName }} +imagePullSecrets: +- name: {{ .Values.controller.serviceAccount.imagePullSecretName }} +{{- end }} +{{- end }} diff --git a/deployment/charts/nginx-ingress/templates/controller-servicemonitor.yaml b/deployment/charts/nginx-ingress/templates/controller-servicemonitor.yaml new file mode 100644 index 0000000..3638d56 --- /dev/null +++ b/deployment/charts/nginx-ingress/templates/controller-servicemonitor.yaml @@ -0,0 +1,15 @@ +{{- if .Values.controller.serviceMonitor.create }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "nginx-ingress.serviceMonitorName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- toYaml .Values.controller.serviceMonitor.labels | nindent 4 }} +spec: + selector: + matchLabels: + {{- toYaml .Values.controller.serviceMonitor.selectorMatchLabels | nindent 6 }} + endpoints: + {{- toYaml .Values.controller.serviceMonitor.endpoints | nindent 4 }} +{{- end }} diff --git a/deployment/charts/nginx-ingress/templates/controller-wildcard-secret.yaml b/deployment/charts/nginx-ingress/templates/controller-wildcard-secret.yaml new file mode 100644 index 0000000..3abe16c --- /dev/null +++ b/deployment/charts/nginx-ingress/templates/controller-wildcard-secret.yaml @@ -0,0 +1,13 @@ +{{ if and (not .Values.controller.wildcardTLS.secret) (and .Values.controller.wildcardTLS.cert .Values.controller.wildcardTLS.key) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "nginx-ingress.wildcardTLSName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "nginx-ingress.labels" . | nindent 4 }} +type: kubernetes.io/tls +data: + tls.crt: {{ .Values.controller.wildcardTLS.cert }} + tls.key: {{ .Values.controller.wildcardTLS.key }} +{{- end }} diff --git a/deployment/charts/nginx-ingress/templates/rbac.yaml b/deployment/charts/nginx-ingress/templates/rbac.yaml new file mode 100644 index 0000000..f107084 --- /dev/null +++ b/deployment/charts/nginx-ingress/templates/rbac.yaml @@ -0,0 +1,204 @@ +{{- if .Values.rbac.create }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "nginx-ingress.name" . }} + labels: + {{- include "nginx-ingress.labels" . | nindent 4 }} +rules: +{{- if .Values.controller.appprotect.enable }} +- apiGroups: + - appprotect.f5.com + resources: + - appolicies + - aplogconfs + - apusersigs + verbs: + - get + - watch + - list +{{- end }} +{{- if .Values.controller.appprotectdos.enable }} +- apiGroups: + - appprotectdos.f5.com + resources: + - apdospolicies + - apdoslogconfs + - dosprotectedresources + verbs: + - get + - watch + - list +{{- end }} +- apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - services + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch +{{- if .Values.controller.reportIngressStatus.enableLeaderElection }} + - update + - create +{{- end }} +- apiGroups: + - "" + resources: + - pods + verbs: + - list + - watch +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + - list +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - update + - create +- apiGroups: + - networking.k8s.io + resources: + - ingresses + verbs: + - get + - list + - watch +- apiGroups: + - networking.k8s.io + resources: + - ingressclasses + verbs: + - get +{{- if .Values.controller.reportIngressStatus.enable }} +- apiGroups: + - networking.k8s.io + resources: + - ingresses/status + verbs: + - update +{{- end }} +{{- if .Values.controller.enableCustomResources }} +- apiGroups: + - k8s.nginx.org + resources: + - virtualservers + - virtualserverroutes + - globalconfigurations + - transportservers + - policies + verbs: + - list + - watch + - get +- apiGroups: + - k8s.nginx.org + resources: + - virtualservers/status + - virtualserverroutes/status + - policies/status + - transportservers/status + verbs: + - update +{{- end }} +{{- if .Values.controller.reportIngressStatus.ingressLink }} +- apiGroups: + - cis.f5.com + resources: + - ingresslinks + verbs: + - list + - watch + - get +{{- end }} +{{- if .Values.controller.enableCertManager }} +- apiGroups: + - cert-manager.io + resources: + - certificates + verbs: + - list + - watch + - get + - update + - create + - delete +{{- end }} +{{- if .Values.controller.enableExternalDNS }} +- apiGroups: + - externaldns.nginx.org + resources: + - dnsendpoints + verbs: + - list + - watch + - get + - update + - create + - delete +- apiGroups: + - externaldns.nginx.org + resources: + - dnsendpoints/status + verbs: + - update +{{- end }} +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "nginx-ingress.name" . }} + labels: + {{- include "nginx-ingress.labels" . | nindent 4 }} +subjects: +- kind: ServiceAccount + name: {{ include "nginx-ingress.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: {{ include "nginx-ingress.name" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} diff --git a/deployment/charts/nginx-ingress/values-icp.yaml b/deployment/charts/nginx-ingress/values-icp.yaml new file mode 100644 index 0000000..5a3b809 --- /dev/null +++ b/deployment/charts/nginx-ingress/values-icp.yaml @@ -0,0 +1,16 @@ +controller: + kind: daemonset + nginxplus: true + image: + repository: mycluster.icp:8500/kube-system/nginx-plus-ingress + tag: "3.0.1" + nodeSelector: + beta.kubernetes.io/arch: "amd64" + proxy: true + terminationGracePeriodSeconds: 60 + tolerations: + - key: "dedicated" + operator: "Exists" + effect: "NoSchedule" + - key: "CriticalAddonsOnly" + operator: "Exists" diff --git a/deployment/charts/nginx-ingress/values-nsm.yaml b/deployment/charts/nginx-ingress/values-nsm.yaml new file mode 100644 index 0000000..60e91a9 --- /dev/null +++ b/deployment/charts/nginx-ingress/values-nsm.yaml @@ -0,0 +1,5 @@ +controller: + enableLatencyMetrics: true +nginxServiceMesh: + enable: true + enableEgress: true diff --git a/deployment/charts/nginx-ingress/values-plus.yaml b/deployment/charts/nginx-ingress/values-plus.yaml new file mode 100644 index 0000000..a830276 --- /dev/null +++ b/deployment/charts/nginx-ingress/values-plus.yaml @@ -0,0 +1,5 @@ +controller: + nginxplus: true + image: + repository: nginx-plus-ingress + tag: "3.0.1" diff --git a/deployment/charts/nginx-ingress/values.schema.json b/deployment/charts/nginx-ingress/values.schema.json new file mode 100644 index 0000000..932e96e --- /dev/null +++ b/deployment/charts/nginx-ingress/values.schema.json @@ -0,0 +1,1686 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "type": "object", + "default": {}, + "title": "Root Schema", + "required": [ + "controller", + "rbac", + "prometheus", + "serviceInsight", + "nginxServiceMesh" + ], + "properties": { + "controller": { + "type": "object", + "default": {}, + "title": "The Ingress Controller Helm Schema", + "required": [ + "kind", + "image" + ], + "properties": { + "name": { + "type": "string", + "default": "", + "title": "The name of the Ingress Controller", + "examples": [ + "nginx-ingress" + ] + }, + "kind": { + "type": "string", + "default": "", + "title": "The kind of the Ingress Controller", + "enum": [ + "deployment", + "daemonset" + ], + "examples": [ + "deployment", + "daemonset" + ] + }, + "annotations": { + "type": "object", + "default": {}, + "title": "The annotations Schema", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/annotations" + }, + "nginxplus": { + "type": "boolean", + "default": false, + "title": "Deploys the Ingress Controller for NGINX Plus", + "examples": [ + false, + true + ] + }, + "nginxReloadTimeout": { + "type": "integer", + "default": 0, + "title": "Timeout in milliseconds which the Ingress Controller will wait for a successful NGINX reload after a change or at the initial start", + "examples": [ + 60000 + ] + }, + "appprotect": { + "type": "object", + "default": {}, + "title": "The App Protect WAF Schema", + "required": [ + "enable" + ], + "properties": { + "enable": { + "type": "boolean", + "default": false, + "title": "Enable the App Protect WAF module in the Ingress Controller", + "examples": [ + false, + true + ] + }, + "logLevel": { + "type": "string", + "default": "", + "title": "The logLevel for App Protect WAF", + "enum": [ + "fatal", + "error", + "warn", + "info", + "debug", + "trace" + ], + "examples": [ + "fatal", + "error", + "warn", + "info", + "debug", + "trace" + ] + } + }, + "examples": [ + { + "enable": true, + "logLevel": "fatal" + } + ] + }, + "appprotectdos": { + "type": "object", + "default": {}, + "title": "The App Protect DoS Schema", + "required": [ + "enable" + ], + "properties": { + "enable": { + "type": "boolean", + "default": false, + "title": "Enable the App Protect DoS module in the Ingress Controller", + "examples": [ + false, + true + ] + }, + "debug": { + "type": "boolean", + "default": false, + "title": "debugging for App Protect DoS", + "examples": [ + false, + true + ] + }, + "maxWorkers": { + "type": "integer", + "default": 0, + "title": "Max number of nginx processes to support", + "examples": [ + 0 + ] + }, + "maxDaemons": { + "type": "integer", + "default": 0, + "title": "Max number of ADMD instances", + "examples": [ + 0 + ] + }, + "memory": { + "type": "integer", + "default": 0, + "title": "RAM memory size to consume in MB", + "examples": [ + 0 + ] + } + }, + "examples": [ + { + "enable": true, + "debug": false, + "maxWorkers": 0, + "maxDaemons": 0, + "memory": 0 + } + ] + }, + "hostNetwork": { + "type": "boolean", + "default": false, + "title": "The hostNetwork Schema", + "examples": [ + false, + true + ] + }, + "dnsPolicy": { + "type": "string", + "allOf": [ + { + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.PodSpec/properties/dnsPolicy" + }, + { + "enum": [ + "ClusterFirstWithHostNet", + "ClusterFirst", + "Default", + "None" + ] + } + ] + }, + "nginxDebug": { + "type": "boolean", + "default": false, + "title": "Enables debugging for NGINX", + "examples": [ + false, + true + ] + }, + "logLevel": { + "type": "integer", + "default": 1, + "title": "The logLevel of the Ingress Controller", + "enum": [ + 0, + 1, + 2, + 3 + ], + "examples": [ + 1 + ] + }, + "customPorts": { + "type": "array", + "default": [], + "title": "The customPorts to expose on the NGINX Ingress Controller pod", + "items": { + "type": "object", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.ContainerPort" + }, + "examples": [ + [ + { + "name": "http", + "containerPort": 80, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 443, + "protocol": "TCP" + } + ] + ] + }, + "image": { + "type": "object", + "default": {}, + "title": "The image Schema", + "required": [ + "repository", + "tag" + ], + "properties": { + "repository": { + "type": "string", + "default": "nginx/nginx-ingress", + "title": "The repository of the Ingress Controller", + "examples": [ + "nginx/nginx-ingress" + ] + }, + "tag": { + "type": "string", + "default": "2.3.1", + "title": "The tag of the Ingress Controller image", + "examples": [ + "2.3.1" + ] + }, + "digest": { + "type": "string", + "default": "", + "title": "The digest of the Ingress Controller image", + "examples": [ + "sha256:2710c264e8eaeb663cee63db37b75a1ac1709f63a130fb091c843a6c3a4dc572" + ] + }, + "pullPolicy": { + "type": "string", + "default": "IfNotPresent", + "title": "The pullPolicy for the Ingress Controller image", + "allOf": [ + { + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.Container/properties/imagePullPolicy" + }, + { + "enum": [ + "Always", + "IfNotPresent", + "Never" + ] + } + ], + "examples": [ + "Always", + "IfNotPresent", + "Never" + ] + } + }, + "examples": [ + { + "repository": "nginx/nginx-ingress", + "tag": "2.3.1", + "pullPolicy": "IfNotPresent" + } + ] + }, + "lifecycle": { + "type": "object", + "default": {}, + "title": "The lifecycle Schema", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.Lifecycle" + }, + "customConfigMap": { + "type": "string", + "default": "", + "title": "The customConfigMap Schema", + "examples": [ + "" + ] + }, + "config": { + "type": "object", + "default": {}, + "title": "The config Schema", + "required": [], + "properties": { + "name": { + "type": "string", + "default": "", + "title": "The name Schema", + "examples": [ + "" + ] + }, + "annotations": { + "type": "object", + "default": {}, + "title": "The annotations Schema", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/annotations" + }, + "entries": { + "type": "object", + "default": {}, + "title": "The entries Schema", + "required": [], + "properties": {}, + "examples": [ + {} + ] + } + }, + "examples": [ + { + "name": "", + "annotations": {}, + "entries": {} + } + ] + }, + "defaultTLS": { + "type": "object", + "default": {}, + "title": "The defaultTLS Schema", + "required": [], + "properties": { + "cert": { + "type": "string", + "default": "", + "title": "The cert Schema", + "examples": [] + }, + "key": { + "type": "string", + "default": "", + "title": "The key Schema", + "examples": [] + }, + "secret": { + "type": "string", + "default": "", + "title": "The secret Schema", + "examples": [ + "" + ] + } + }, + "examples": [] + }, + "wildcardTLS": { + "type": "object", + "default": {}, + "title": "The wildcardTLS Schema", + "required": [], + "properties": { + "cert": { + "type": "string", + "default": "", + "title": "The cert Schema", + "examples": [ + "" + ] + }, + "key": { + "type": "string", + "default": "", + "title": "The key Schema", + "examples": [ + "" + ] + }, + "secret": { + "type": "string", + "default": "", + "title": "The secret Schema", + "examples": [ + "" + ] + } + }, + "examples": [] + }, + "nodeSelector": { + "type": "object", + "default": {}, + "title": "The nodeSelector Schema", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.PodSpec/properties/nodeSelector" + }, + "terminationGracePeriodSeconds": { + "type": "integer", + "default": 30, + "title": "The terminationGracePeriodSeconds Schema", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.PodSpec/properties/terminationGracePeriodSeconds" + }, + "resources": { + "type": "object", + "default": {}, + "title": "The resources Schema", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.ResourceRequirements" + }, + "tolerations": { + "type": "array", + "default": [], + "title": "The tolerations Schema", + "items": { + "type": "object", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.Toleration" + } + }, + "affinity": { + "type": "object", + "default": {}, + "title": "The affinity Schema", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.Affinity" + }, + "topologySpreadConstraints": { + "type": "object", + "default": {}, + "title": "The topologySpreadConstraints Schema", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.TopologySpreadConstraint" + }, + "volumes": { + "type": "array", + "default": [], + "title": "The volumes Schema", + "items": { + "type": "object", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.Volume" + } + }, + "volumeMounts": { + "type": "array", + "default": [], + "title": "The volumeMounts Schema", + "items": { + "type": "object", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.VolumeMount" + } + }, + "initContainers": { + "type": "array", + "default": [], + "title": "The initContainers Schema", + "items": { + "type": "object", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.Container" + } + }, + "minReadySeconds": { + "type": "integer", + "default": 0, + "title": "The minReadySeconds Schema", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.apps.v1.DeploymentSpec/properties/minReadySeconds" + }, + "strategy": { + "type": "object", + "default": {}, + "title": "The strategy Schema", + "allOf": [ + { + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.apps.v1.DeploymentStrategy" + }, + { + "properties": { + "type": { + "type": "string", + "enum": [ + "Recreate", + "RollingUpdate" + ] + } + } + } + ] + }, + "extraContainers": { + "type": "array", + "default": [], + "title": "The extraContainers Schema", + "items": { + "type": "object", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.Container" + } + }, + "replicaCount": { + "type": "integer", + "default": 1, + "title": "The replicaCount", + "examples": [ + 1 + ] + }, + "ingressClass": { + "type": "string", + "default": "", + "title": "The ingressClass", + "examples": [ + "nginx" + ] + }, + "setAsDefaultIngress": { + "type": "boolean", + "default": false, + "title": "The setAsDefaultIngress", + "examples": [ + false + ] + }, + "watchNamespace": { + "type": "string", + "default": "", + "title": "The watchNamespace", + "examples": [ + "" + ] + }, + "watchSecretNamespace": { + "type": "string", + "default": "", + "title": "The watchSecretNamespace", + "examples": [ + "" + ] + }, + "enableCustomResources": { + "type": "boolean", + "default": false, + "title": "The enableCustomResources", + "examples": [ + true + ] + }, + "enablePreviewPolicies": { + "type": "boolean", + "default": false, + "title": "The enablePreviewPolicies", + "examples": [ + false + ] + }, + "enableOIDC": { + "type": "boolean", + "default": false, + "title": "The enableOIDC", + "examples": [ + false + ] + }, + "includeYear": { + "type": "boolean", + "default": false, + "title": "The includeYear", + "examples": [ + false + ] + }, + "enableTLSPassthrough": { + "type": "boolean", + "default": false, + "title": "The enableTLSPassthrough", + "examples": [ + false + ] + }, + "enableCertManager": { + "type": "boolean", + "default": false, + "title": "The enableCertManager", + "examples": [ + false + ] + }, + "enableExternalDNS": { + "type": "boolean", + "default": false, + "title": "The enableExternalDNS", + "examples": [ + false + ] + }, + "globalConfiguration": { + "type": "object", + "default": {}, + "title": "The globalConfiguration Schema", + "required": [ + "create", + "spec" + ], + "properties": { + "create": { + "type": "boolean", + "default": false, + "title": "The create Schema", + "examples": [ + false + ] + }, + "spec": { + "type": "object", + "default": {}, + "title": "The spec Schema", + "required": [], + "properties": { + "listeners": { + "type": "array", + "default": [], + "title": "The listeners Schema", + "items": { + "type": "object", + "default": {}, + "properties": { + "port": { + "type": "integer", + "default": 0, + "title": "The port", + "examples": [ + 5353 + ] + }, + "protocol": { + "type": "string", + "default": "", + "title": "The protocol", + "examples": [ + "TCP" + ] + }, + "name": { + "type": "string", + "default": "", + "title": "The name", + "examples": [ + "dns-tcp" + ] + } + } + } + } + }, + "examples": [ + {} + ] + } + }, + "examples": [ + { + "create": false, + "spec": {} + } + ] + }, + "enableSnippets": { + "type": "boolean", + "default": false, + "title": "The enableSnippets", + "examples": [ + false + ] + }, + "healthStatus": { + "type": "boolean", + "default": false, + "title": "The healthStatus", + "examples": [ + false + ] + }, + "healthStatusURI": { + "type": "string", + "format": "uri-reference", + "default": "/nginx-health", + "title": "The healthStatusURI Schema", + "examples": [ + "/nginx-health" + ] + }, + "nginxStatus": { + "type": "object", + "default": {}, + "title": "The nginxStatus Schema", + "required": [], + "properties": { + "enable": { + "type": "boolean", + "default": false, + "title": "The enable", + "examples": [ + true + ] + }, + "port": { + "type": "integer", + "default": 8080, + "title": "The port", + "examples": [ + 8080 + ] + }, + "allowCidrs": { + "type": "string", + "default": "127.0.0.1", + "title": "The allowCidrs", + "examples": [ + "127.0.0.1" + ] + } + }, + "examples": [ + { + "enable": true, + "port": 8080, + "allowCidrs": "127.0.0.1" + } + ] + }, + "service": { + "type": "object", + "default": {}, + "title": "The service Schema", + "required": [], + "properties": { + "create": { + "type": "boolean", + "default": false, + "title": "The create", + "examples": [ + true + ] + }, + "type": { + "type": "string", + "default": "", + "title": "The type", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.ServiceSpec/properties/type" + }, + "externalTrafficPolicy": { + "type": "string", + "default": "", + "title": "The externalTrafficPolicy", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.ServiceSpec/properties/externalTrafficPolicy" + }, + "annotations": { + "type": "object", + "default": {}, + "title": "The annotations", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/annotations" + }, + "extraLabels": { + "type": "object", + "default": {}, + "title": "The extraLabels", + "required": [], + "properties": {}, + "examples": [ + {} + ] + }, + "loadBalancerIP": { + "type": "string", + "default": "", + "title": "The loadBalancerIP", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.ServiceSpec/properties/loadBalancerIP" + }, + "externalIPs": { + "type": "array", + "default": [], + "title": "The externalIPs", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.ServiceSpec/properties/externalIPs" + }, + "loadBalancerSourceRanges": { + "type": "array", + "default": [], + "title": "The loadBalancerSourceRanges", + "items": {}, + "examples": [ + [] + ] + }, + "name": { + "type": "string", + "default": "", + "title": "The name", + "examples": [ + "" + ] + }, + "allocateLoadBalancerNodePorts": { + "type": "boolean", + "default": false, + "title": "The allocateLoadBalancerNodePorts Schema", + "ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.ServiceSpec/properties/allocateLoadBalancerNodePorts" + }, + "ipFamilyPolicy": { + "type": "string", + "default": "", + "title": "The ipFamilyPolicy Schema", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.ServiceSpec/properties/ipFamilyPolicy", + "examples": [ + "" + ] + }, + "ipFamilies": { + "type": "array", + "default": [], + "title": "The ipFamilies Schema", + "ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.ServiceSpec/properties/ipFamilies" + }, + "httpPort": { + "type": "object", + "default": {}, + "title": "The httpPort", + "required": [], + "properties": { + "enable": { + "type": "boolean", + "default": false, + "title": "The enable", + "examples": [ + true + ] + }, + "port": { + "type": "integer", + "default": 0, + "title": "The port", + "examples": [ + 80 + ] + }, + "nodePort": { + "type": "integer", + "default": 0, + "title": "The nodePort", + "examples": [ + 443 + ] + }, + "targetPort": { + "type": "integer", + "default": 0, + "title": "The targetPort", + "examples": [ + 80 + ] + } + }, + "examples": [ + { + "enable": true, + "port": 80, + "nodePort": "", + "targetPort": 80 + } + ] + }, + "httpsPort": { + "type": "object", + "default": {}, + "title": "The httpsPort", + "required": [], + "properties": { + "enable": { + "type": "boolean", + "default": false, + "title": "The enable", + "examples": [ + true + ] + }, + "port": { + "type": "integer", + "default": 0, + "title": "The port", + "examples": [ + 443 + ] + }, + "nodePort": { + "type": "integer", + "default": 0, + "title": "The nodePort", + "examples": [ + 443 + ] + }, + "targetPort": { + "type": "integer", + "default": 0, + "title": "The targetPort", + "examples": [ + 443 + ] + } + }, + "examples": [ + { + "enable": true, + "port": 443, + "nodePort": "", + "targetPort": 443 + } + ] + }, + "customPorts": { + "type": "array", + "default": [], + "title": "The customPorts", + "items": { + "type": "object", + "ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.ServicePort" + } + } + }, + "examples": [ + { + "create": true, + "type": "LoadBalancer", + "externalTrafficPolicy": "Local", + "annotations": {}, + "extraLabels": {}, + "loadBalancerIP": "", + "externalIPs": [], + "loadBalancerSourceRanges": [], + "name": "", + "allocateLoadBalancerNodePorts": false, + "ipFamilyPolicy": "", + "ipFamilies": [], + "httpPort": { + "enable": true, + "port": 80, + "targetPort": 80 + }, + "httpsPort": { + "enable": true, + "port": 443, + "targetPort": 443 + }, + "customPorts": [] + } + ] + }, + "serviceAccount": { + "type": "object", + "default": {}, + "title": "The serviceAccount Schema", + "required": [], + "properties": { + "annotations": { + "type": "object", + "default": {}, + "title": "The annotations Schema", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/annotations" + }, + "name": { + "type": "string", + "default": "", + "title": "The name Schema", + "examples": [ + "" + ] + }, + "imagePullSecretName": { + "type": "string", + "default": "", + "title": "The imagePullSecretName", + "examples": [ + "" + ] + } + }, + "examples": [ + { + "name": "", + "imagePullSecretName": "" + } + ] + }, + "serviceMonitor": { + "type": "object", + "default": {}, + "title": "The serviceMonitor Schema", + "required": [], + "properties": { + "create": { + "type": "boolean", + "default": false, + "title": "The create", + "examples": [ + false + ] + }, + "name": { + "type": "string", + "default": "", + "title": "The name", + "examples": [ + "" + ] + }, + "labels": { + "type": "object", + "default": {}, + "title": "The labels Schema", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/labels" + }, + "selectorMatchLabels": { + "type": "object", + "default": {}, + "title": "The selectorMatchLabels Schema", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector/properties/matchLabels" + }, + "endpoints": { + "type": "array", + "default": [], + "title": "The endpoints", + "required": [], + "items": {} + } + }, + "examples": [ + { + "create": false, + "name": "", + "labels": {}, + "selectorMatchLabels": {}, + "endpoints": [] + } + ] + }, + "reportIngressStatus": { + "type": "object", + "default": {}, + "title": "The reportIngressStatus Schema", + "required": [ + "enable" + ], + "properties": { + "enable": { + "type": "boolean", + "default": false, + "title": "The enable", + "examples": [ + true + ] + }, + "externalService": { + "type": "string", + "default": "", + "title": "The externalService", + "examples": [ + "" + ] + }, + "ingressLink": { + "type": "string", + "default": "", + "title": "The ingressLink", + "examples": [ + "" + ] + }, + "enableLeaderElection": { + "type": "boolean", + "default": false, + "title": "The enableLeaderElection", + "examples": [ + true + ] + }, + "leaderElectionLockName": { + "type": "string", + "default": "", + "title": "The leaderElectionLockName", + "examples": [ + "" + ] + }, + "annotations": { + "type": "object", + "default": {}, + "title": "The annotations Schema", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/annotations" + } + }, + "examples": [ + { + "enable": true, + "externalService": "", + "ingressLink": "", + "enableLeaderElection": true, + "leaderElectionLockName": "", + "annotations": {} + } + ] + }, + "pod": { + "type": "object", + "default": {}, + "title": "The pod Schema", + "required": [], + "properties": { + "annotations": { + "type": "object", + "default": {}, + "title": "The annotations Schema", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/annotations" + }, + "extraLabels": { + "type": "object", + "default": {}, + "title": "The extraLabels Schema", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/labels" + } + }, + "examples": [ + { + "annotations": {}, + "extraLabels": {} + } + ] + }, + "priorityClassName": { + "type": "string", + "default": "", + "title": "The priorityClassName", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.PodSpec/properties/priorityClassName" + }, + "readyStatus": { + "type": "object", + "default": {}, + "title": "The readyStatus", + "required": [], + "properties": { + "enable": { + "type": "boolean", + "default": false, + "title": "The enable", + "examples": [ + true + ] + }, + "port": { + "type": "integer", + "default": 0, + "title": "The port", + "examples": [ + 8081 + ] + }, + "initialDelaySeconds": { + "type": "integer", + "default": 0, + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.25.4/_definitions.json#/definitions/io.k8s.api.core.v1.Probe/properties/initialDelaySeconds" + } + }, + "examples": [ + { + "enable": true, + "port": 8081, + "initialDelaySeconds": 0 + } + ] + }, + "enableLatencyMetrics": { + "type": "boolean", + "default": false, + "title": "The enableLatencyMetrics", + "examples": [ + false + ] + }, + "disableIPV6": { + "type": "boolean", + "default": false, + "title": "The disableIPV6", + "examples": [ + false + ] + } + }, + "examples": [ + { + "name": "", + "kind": "deployment", + "nginxplus": false, + "nginxReloadTimeout": 60000, + "appprotect": { + "enable": false, + "logLevel": "fatal" + }, + "appprotectdos": { + "enable": false, + "debug": false, + "maxWorkers": 0, + "maxDaemons": 0, + "memory": 0 + }, + "hostNetwork": false, + "nginxDebug": false, + "logLevel": 1, + "customPorts": [], + "image": { + "repository": "nginx/nginx-ingress", + "tag": "2.3.1", + "digest": "", + "pullPolicy": "IfNotPresent" + }, + "lifecycle": {}, + "customConfigMap": "", + "config": { + "name": "", + "annotations": {}, + "entries": {} + }, + "defaultTLS": { + "cert": "", + "key": "", + "secret": "" + }, + "wildcardTLS": { + "cert": "", + "key": "", + "secret": "" + }, + "nodeSelector": {}, + "terminationGracePeriodSeconds": 30, + "resources": { + "requests": { + "cpu": "100m", + "memory": "128Mi" + } + }, + "tolerations": [], + "affinity": {}, + "topologySpreadConstraints": {}, + "volumes": [], + "volumeMounts": [], + "initContainers": [], + "minReadySeconds": 0, + "strategy": {}, + "extraContainers": [], + "replicaCount": 1, + "ingressClass": "nginx", + "setAsDefaultIngress": false, + "watchNamespace": "", + "enableCustomResources": true, + "enablePreviewPolicies": false, + "enableOIDC": false, + "includeYear": false, + "enableTLSPassthrough": false, + "enableCertManager": false, + "enableExternalDNS": false, + "globalConfiguration": { + "create": false, + "spec": {} + }, + "enableSnippets": false, + "healthStatus": false, + "healthStatusURI": "/nginx-health", + "nginxStatus": { + "enable": true, + "port": 8080, + "allowCidrs": "127.0.0.1" + }, + "service": { + "create": true, + "type": "LoadBalancer", + "externalTrafficPolicy": "Local", + "annotations": {}, + "extraLabels": {}, + "loadBalancerIP": "", + "externalIPs": [], + "loadBalancerSourceRanges": [], + "name": "", + "allocateLoadBalancerNodePorts": false, + "ipFamilyPolicy": "", + "ipFamilies": [], + "httpPort": { + "enable": true, + "port": 80, + "targetPort": 80 + }, + "httpsPort": { + "enable": true, + "port": 443, + "targetPort": 443 + }, + "customPorts": [] + }, + "serviceAccount": { + "name": "", + "imagePullSecretName": "" + }, + "serviceMonitor": { + "create": false, + "name": "", + "labels": {}, + "selectorMatchLabels": {}, + "endpoints": {} + }, + "reportIngressStatus": { + "enable": true, + "externalService": "", + "ingressLink": "", + "enableLeaderElection": true, + "leaderElectionLockName": "", + "annotations": {} + }, + "pod": { + "annotations": {}, + "extraLabels": {} + }, + "priorityClassName": "", + "readyStatus": { + "enable": true, + "port": 8081, + "initialDelaySeconds": 0 + }, + "enableLatencyMetrics": false, + "disableIPV6": false + } + ] + }, + "rbac": { + "type": "object", + "default": {}, + "title": "The rbac Schema", + "required": [ + "create" + ], + "properties": { + "create": { + "type": "boolean", + "default": false, + "title": "The create Schema", + "examples": [ + true + ] + } + }, + "examples": [ + { + "create": true + } + ] + }, + "prometheus": { + "type": "object", + "default": {}, + "title": "The prometheus Schema", + "required": [ + "create" + ], + "properties": { + "create": { + "type": "boolean", + "default": false, + "title": "The create", + "examples": [ + true + ] + }, + "port": { + "type": "integer", + "default": 9113, + "title": "The port", + "examples": [ + 9113 + ] + }, + "secret": { + "type": "string", + "default": "", + "title": "The secret", + "examples": [ + "" + ] + }, + "scheme": { + "type": "string", + "default": "http", + "title": "The scheme", + "examples": [ + "http" + ] + } + }, + "examples": [ + { + "create": true, + "port": 9113, + "secret": "", + "scheme": "http" + } + ] + }, + "serviceInsight": { + "type": "object", + "default": {}, + "title": "The Service Insight Schema", + "required": [ + "create" + ], + "properties": { + "create": { + "type": "boolean", + "default": false, + "title": "The create", + "examples": [ + true + ] + }, + "port": { + "type": "integer", + "default": 9114, + "title": "The port", + "examples": [ + 9114 + ] + }, + "secret": { + "type": "string", + "default": "", + "title": "The secret", + "examples": [ + "" + ] + }, + "scheme": { + "type": "string", + "default": "http", + "title": "The scheme", + "examples": [ + "http" + ] + } + }, + "examples": [ + { + "create": true, + "port": 9114, + "secret": "", + "scheme": "http" + } + ] + }, + "nginxServiceMesh": { + "type": "object", + "default": {}, + "title": "The nginxServiceMesh Schema", + "required": [ + "enable" + ], + "properties": { + "enable": { + "type": "boolean", + "default": false, + "title": "The enable", + "examples": [ + false + ] + }, + "enableEgress": { + "type": "boolean", + "default": false, + "title": "The enableEgress", + "examples": [ + false + ] + } + }, + "examples": [ + { + "enable": false, + "enableEgress": false + } + ] + } + }, + "examples": [ + { + "controller": { + "name": "", + "kind": "deployment", + "nginxplus": false, + "nginxReloadTimeout": 60000, + "appprotect": { + "enable": false, + "logLevel": "fatal" + }, + "appprotectdos": { + "enable": false, + "debug": false, + "maxWorkers": 0, + "maxDaemons": 0, + "memory": 0 + }, + "hostNetwork": false, + "nginxDebug": false, + "logLevel": 1, + "customPorts": [], + "image": { + "repository": "nginx/nginx-ingress", + "tag": "2.3.1", + "digest": "", + "pullPolicy": "IfNotPresent" + }, + "lifecycle": {}, + "customConfigMap": "", + "config": { + "name": "", + "annotations": {}, + "entries": {} + }, + "defaultTLS": { + "cert": "", + "key": "", + "secret": "" + }, + "wildcardTLS": { + "cert": "", + "key": "", + "secret": "" + }, + "nodeSelector": {}, + "terminationGracePeriodSeconds": 30, + "resources": { + "requests": { + "cpu": "100m", + "memory": "128Mi" + } + }, + "tolerations": [], + "affinity": {}, + "topologySpreadConstraints": {}, + "volumes": [], + "volumeMounts": [], + "initContainers": [], + "minReadySeconds": 0, + "strategy": {}, + "extraContainers": [], + "replicaCount": 1, + "ingressClass": "nginx", + "setAsDefaultIngress": false, + "watchNamespace": "", + "enableCustomResources": true, + "enablePreviewPolicies": false, + "enableOIDC": false, + "includeYear": false, + "enableTLSPassthrough": false, + "enableCertManager": false, + "enableExternalDNS": false, + "globalConfiguration": { + "create": false, + "spec": {} + }, + "enableSnippets": false, + "healthStatus": false, + "healthStatusURI": "/nginx-health", + "nginxStatus": { + "enable": true, + "port": 8080, + "allowCidrs": "127.0.0.1" + }, + "service": { + "create": true, + "type": "LoadBalancer", + "externalTrafficPolicy": "Local", + "annotations": {}, + "extraLabels": {}, + "loadBalancerIP": "", + "externalIPs": [], + "loadBalancerSourceRanges": [], + "name": "", + "allocateLoadBalancerNodePorts": false, + "ipFamilyPolicy": "", + "ipFamilies": [], + "httpPort": { + "enable": true, + "port": 80, + "nodePort": "", + "targetPort": 80 + }, + "httpsPort": { + "enable": true, + "port": 443, + "nodePort": "", + "targetPort": 443 + }, + "customPorts": [] + }, + "serviceAccount": { + "name": "", + "imagePullSecretName": "" + }, + "serviceMonitor": { + "create": false, + "name": "", + "labels": {}, + "selectorMatchLabels": {}, + "endpoints": {} + }, + "reportIngressStatus": { + "enable": true, + "externalService": "", + "ingressLink": "", + "enableLeaderElection": true, + "leaderElectionLockName": "", + "annotations": {} + }, + "pod": { + "annotations": {}, + "extraLabels": {} + }, + "priorityClassName": "", + "readyStatus": { + "enable": true, + "port": 8081, + "initialDelaySeconds": 0 + }, + "enableLatencyMetrics": false, + "disableIPV6": false + }, + "rbac": { + "create": true + }, + "prometheus": { + "create": true, + "port": 9113, + "secret": "", + "scheme": "http" + }, + "serviceInsight": { + "create": true, + "port": 9114, + "secret": "", + "scheme": "http" + }, + "nginxServiceMesh": { + "enable": false, + "enableEgress": false + } + } + ] +} diff --git a/deployment/charts/nginx-ingress/values.yaml b/deployment/charts/nginx-ingress/values.yaml new file mode 100644 index 0000000..844104e --- /dev/null +++ b/deployment/charts/nginx-ingress/values.yaml @@ -0,0 +1,455 @@ +controller: + ## The name of the Ingress Controller daemonset or deployment. + ## Autogenerated if not set or set to "". + # name: nginx-ingress + + ## The kind of the Ingress Controller installation - deployment or daemonset. + kind: deployment + + ## Annotations for deployments and daemonsets + annotations: {} + + ## Deploys the Ingress Controller for NGINX Plus. + nginxplus: false + + # Timeout in milliseconds which the Ingress Controller will wait for a successful NGINX reload after a change or at the initial start. + nginxReloadTimeout: 60000 + + ## Support for App Protect WAF + appprotect: + ## Enable the App Protect WAF module in the Ingress Controller. + enable: false + ## Sets log level for App Protect WAF. Allowed values: fatal, error, warn, info, debug, trace + # logLevel: fatal + + ## Support for App Protect DoS + appprotectdos: + ## Enable the App Protect DoS module in the Ingress Controller. + enable: false + ## Enable debugging for App Protect DoS. + debug: false + ## Max number of nginx processes to support. + maxWorkers: 0 + ## Max number of ADMD instances. + maxDaemons: 0 + ## RAM memory size to consume in MB. + memory: 0 + + ## Enables the Ingress Controller pods to use the host's network namespace. + hostNetwork: false + + ## DNS policy for the Ingress Controller pods + dnsPolicy: ClusterFirst + + ## Enables debugging for NGINX. Uses the nginx-debug binary. Requires error-log-level: debug in the ConfigMap via `controller.config.entries`. + nginxDebug: false + + ## The log level of the Ingress Controller. + logLevel: 1 + + ## A list of custom ports to expose on the NGINX Ingress Controller pod. Follows the conventional Kubernetes yaml syntax for container ports. + customPorts: [] + + image: + ## The image repository of the Ingress Controller. + repository: nginx/nginx-ingress + + ## The tag of the Ingress Controller image. + tag: "3.0.1" + + ## The digest of the Ingress Controller image. + ## If digest is specified it has precedence over tag and will be used instead + # digest: "sha256:CHANGEME" + + ## The pull policy for the Ingress Controller image. + pullPolicy: IfNotPresent + + ## The lifecycle of the Ingress Controller pods. + lifecycle: {} + + ## The custom ConfigMap to use instead of the one provided by default + customConfigMap: "" + + config: + ## The name of the ConfigMap used by the Ingress Controller. + ## Autogenerated if not set or set to "". + # name: nginx-config + + ## The annotations of the Ingress Controller configmap. + annotations: {} + + ## The entries of the ConfigMap for customizing NGINX configuration. + entries: {} + + ## It is recommended to use your own TLS certificates and keys + defaultTLS: + ## The base64-encoded TLS certificate for the default HTTPS server. By default, a pre-generated self-signed certificate is used. + ## Note: It is recommended that you specify your own certificate. Alternatively, omitting the default server secret completely will configure NGINX to reject TLS connections to the default server. + cert: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN2akNDQWFZQ0NRREFPRjl0THNhWFhEQU5CZ2txaGtpRzl3MEJBUXNGQURBaE1SOHdIUVlEVlFRRERCWk8KUjBsT1dFbHVaM0psYzNORGIyNTBjbTlzYkdWeU1CNFhEVEU0TURreE1qRTRNRE16TlZvWERUSXpNRGt4TVRFNApNRE16TlZvd0lURWZNQjBHQTFVRUF3d1dUa2RKVGxoSmJtZHlaWE56UTI5dWRISnZiR3hsY2pDQ0FTSXdEUVlKCktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQUwvN2hIUEtFWGRMdjNyaUM3QlBrMTNpWkt5eTlyQ08KR2xZUXYyK2EzUDF0azIrS3YwVGF5aGRCbDRrcnNUcTZzZm8vWUk1Y2Vhbkw4WGM3U1pyQkVRYm9EN2REbWs1Qgo4eDZLS2xHWU5IWlg0Rm5UZ0VPaStlM2ptTFFxRlBSY1kzVnNPazFFeUZBL0JnWlJVbkNHZUtGeERSN0tQdGhyCmtqSXVuektURXUyaDU4Tlp0S21ScUJHdDEwcTNRYzhZT3ExM2FnbmovUWRjc0ZYYTJnMjB1K1lYZDdoZ3krZksKWk4vVUkxQUQ0YzZyM1lma1ZWUmVHd1lxQVp1WXN2V0RKbW1GNWRwdEMzN011cDBPRUxVTExSakZJOTZXNXIwSAo1TmdPc25NWFJNV1hYVlpiNWRxT3R0SmRtS3FhZ25TZ1JQQVpQN2MwQjFQU2FqYzZjNGZRVXpNQ0F3RUFBVEFOCkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQWpLb2tRdGRPcEsrTzhibWVPc3lySmdJSXJycVFVY2ZOUitjb0hZVUoKdGhrYnhITFMzR3VBTWI5dm15VExPY2xxeC9aYzJPblEwMEJCLzlTb0swcitFZ1U2UlVrRWtWcitTTFA3NTdUWgozZWI4dmdPdEduMS9ienM3bzNBaS9kclkrcUI5Q2k1S3lPc3FHTG1US2xFaUtOYkcyR1ZyTWxjS0ZYQU80YTY3Cklnc1hzYktNbTQwV1U3cG9mcGltU1ZmaXFSdkV5YmN3N0NYODF6cFErUyt1eHRYK2VBZ3V0NHh3VlI5d2IyVXYKelhuZk9HbWhWNThDd1dIQnNKa0kxNXhaa2VUWXdSN0diaEFMSkZUUkk3dkhvQXprTWIzbjAxQjQyWjNrN3RXNQpJUDFmTlpIOFUvOWxiUHNoT21FRFZkdjF5ZytVRVJxbStGSis2R0oxeFJGcGZnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= + + ## The base64-encoded TLS key for the default HTTPS server. By default, a pre-generated key is used. + ## Note: It is recommended that you specify your own key. Alternatively, omitting the default server secret completely will configure NGINX to reject TLS connections to the default server. + key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBdi91RWM4b1JkMHUvZXVJTHNFK1RYZUprckxMMnNJNGFWaEMvYjVyYy9XMlRiNHEvClJOcktGMEdYaVN1eE9ycXgrajlnamx4NXFjdnhkenRKbXNFUkJ1Z1B0ME9hVGtIekhvb3FVWmcwZGxmZ1dkT0EKUTZMNTdlT1l0Q29VOUZ4amRXdzZUVVRJVUQ4R0JsRlNjSVo0b1hFTkhzbysyR3VTTWk2Zk1wTVM3YUhudzFtMApxWkdvRWEzWFNyZEJ6eGc2clhkcUNlUDlCMXl3VmRyYURiUzc1aGQzdUdETDU4cGszOVFqVUFQaHpxdmRoK1JWClZGNGJCaW9CbTVpeTlZTW1hWVhsMm0wTGZzeTZuUTRRdFFzdEdNVWozcGJtdlFmazJBNnljeGRFeFpkZFZsdmwKMm82MjBsMllxcHFDZEtCRThCay90elFIVTlKcU56cHpoOUJUTXdJREFRQUJBb0lCQVFDZklHbXowOHhRVmorNwpLZnZJUXQwQ0YzR2MxNld6eDhVNml4MHg4Mm15d1kxUUNlL3BzWE9LZlRxT1h1SENyUlp5TnUvZ2IvUUQ4bUFOCmxOMjRZTWl0TWRJODg5TEZoTkp3QU5OODJDeTczckM5bzVvUDlkazAvYzRIbjAzSkVYNzZ5QjgzQm9rR1FvYksKMjhMNk0rdHUzUmFqNjd6Vmc2d2szaEhrU0pXSzBwV1YrSjdrUkRWYmhDYUZhNk5nMUZNRWxhTlozVDhhUUtyQgpDUDNDeEFTdjYxWTk5TEI4KzNXWVFIK3NYaTVGM01pYVNBZ1BkQUk3WEh1dXFET1lvMU5PL0JoSGt1aVg2QnRtCnorNTZud2pZMy8yUytSRmNBc3JMTnIwMDJZZi9oY0IraVlDNzVWYmcydVd6WTY3TWdOTGQ5VW9RU3BDRkYrVm4KM0cyUnhybnhBb0dCQU40U3M0ZVlPU2huMVpQQjdhTUZsY0k2RHR2S2ErTGZTTXFyY2pOZjJlSEpZNnhubmxKdgpGenpGL2RiVWVTbWxSekR0WkdlcXZXaHFISy9iTjIyeWJhOU1WMDlRQ0JFTk5jNmtWajJTVHpUWkJVbEx4QzYrCk93Z0wyZHhKendWelU0VC84ajdHalRUN05BZVpFS2FvRHFyRG5BYWkyaW5oZU1JVWZHRXFGKzJyQW9HQkFOMVAKK0tZL0lsS3RWRzRKSklQNzBjUis3RmpyeXJpY05iWCtQVzUvOXFHaWxnY2grZ3l4b25BWlBpd2NpeDN3QVpGdwpaZC96ZFB2aTBkWEppc1BSZjRMazg5b2pCUmpiRmRmc2l5UmJYbyt3TFU4NUhRU2NGMnN5aUFPaTVBRHdVU0FkCm45YWFweUNweEFkREtERHdObit3ZFhtaTZ0OHRpSFRkK3RoVDhkaVpBb0dCQUt6Wis1bG9OOTBtYlF4VVh5YUwKMjFSUm9tMGJjcndsTmVCaWNFSmlzaEhYa2xpSVVxZ3hSZklNM2hhUVRUcklKZENFaHFsV01aV0xPb2I2NTNyZgo3aFlMSXM1ZUtka3o0aFRVdnpldm9TMHVXcm9CV2xOVHlGanIrSWhKZnZUc0hpOGdsU3FkbXgySkJhZUFVWUNXCndNdlQ4NmNLclNyNkQrZG8wS05FZzFsL0FvR0FlMkFVdHVFbFNqLzBmRzgrV3hHc1RFV1JqclRNUzRSUjhRWXQKeXdjdFA4aDZxTGxKUTRCWGxQU05rMXZLTmtOUkxIb2pZT2pCQTViYjhibXNVU1BlV09NNENoaFJ4QnlHbmR2eAphYkJDRkFwY0IvbEg4d1R0alVZYlN5T294ZGt5OEp0ek90ajJhS0FiZHd6NlArWDZDODhjZmxYVFo5MWpYL3RMCjF3TmRKS2tDZ1lCbyt0UzB5TzJ2SWFmK2UwSkN5TGhzVDQ5cTN3Zis2QWVqWGx2WDJ1VnRYejN5QTZnbXo5aCsKcDNlK2JMRUxwb3B0WFhNdUFRR0xhUkcrYlNNcjR5dERYbE5ZSndUeThXczNKY3dlSTdqZVp2b0ZpbmNvVlVIMwphdmxoTUVCRGYxSjltSDB5cDBwWUNaS2ROdHNvZEZtQktzVEtQMjJhTmtsVVhCS3gyZzR6cFE9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo= + + ## The secret with a TLS certificate and key for the default HTTPS server. + ## The value must follow the following format: `/`. + ## Used as an alternative to specifying a certificate and key using `controller.defaultTLS.cert` and `controller.defaultTLS.key` parameters. + ## Note: Alternatively, omitting the default server secret completely will configure NGINX to reject TLS connections to the default server. + ## Format: / + secret: "" + + wildcardTLS: + ## The base64-encoded TLS certificate for every Ingress/VirtualServer host that has TLS enabled but no secret specified. + ## If the parameter is not set, for such Ingress/VirtualServer hosts NGINX will break any attempt to establish a TLS connection. + cert: "" + + ## The base64-encoded TLS key for every Ingress/VirtualServer host that has TLS enabled but no secret specified. + ## If the parameter is not set, for such Ingress/VirtualServer hosts NGINX will break any attempt to establish a TLS connection. + key: "" + + ## The secret with a TLS certificate and key for every Ingress/VirtualServer host that has TLS enabled but no secret specified. + ## The value must follow the following format: `/`. + ## Used as an alternative to specifying a certificate and key using `controller.wildcardTLS.cert` and `controller.wildcardTLS.key` parameters. + ## Format: / + secret: "" + + ## The node selector for pod assignment for the Ingress Controller pods. + # nodeSelector: {} + + ## The termination grace period of the Ingress Controller pod. + terminationGracePeriodSeconds: 30 + + ## HorizontalPodAutoscaling (HPA) + autoscaling: + ## Enables HorizontalPodAutoscaling. + enabled: false + ## The annotations of the Ingress Controller HorizontalPodAutoscaler. + annotations: {} + ## Minimum number of replicas for the HPA. + minReplicas: 1 + ## Maximum number of replicas for the HPA. + maxReplicas: 3 + ## The target cpu utilization percentage. + targetCPUUtilizationPercentage: 50 + ## The target memory utilization percentage. + targetMemoryUtilizationPercentage: 50 + + ## The resources of the Ingress Controller pods. + resources: + requests: + cpu: 100m + memory: 128Mi + # limits: + # cpu: 1 + # memory: 1Gi + + + ## The tolerations of the Ingress Controller pods. + tolerations: [] + + ## The affinity of the Ingress Controller pods. + affinity: {} + + ## The topology spread constraints of the Ingress controller pods. + # topologySpreadConstraints: {} + + ## The volumes of the Ingress Controller pods. + volumes: [] + # - name: extra-conf + # configMap: + # name: extra-conf + + ## The volumeMounts of the Ingress Controller pods. + volumeMounts: [] + # - name: extra-conf + # mountPath: /etc/nginx/conf.d/extra.conf + # subPath: extra.conf + + ## InitContainers for the Ingress Controller pods. + initContainers: [] + # - name: init-container + # image: busybox:1.34 + # command: ['sh', '-c', 'echo this is initial setup!'] + + ## The minimum number of seconds for which a newly created Pod should be ready without any of its containers crashing, for it to be considered available. + minReadySeconds: 0 + + ## Strategy used to replace old Pods by new ones. .spec.strategy.type can be "Recreate" or "RollingUpdate". "RollingUpdate" is the default value. + strategy: {} + + ## Extra containers for the Ingress Controller pods. + extraContainers: [] + # - name: container + # image: busybox:1.34 + # command: ['sh', '-c', 'echo this is a sidecar!'] + + ## The number of replicas of the Ingress Controller deployment. + replicaCount: 1 + + ## A class of the Ingress Controller. + + ## IngressClass resource with the name equal to the class must be deployed. Otherwise, + ## the Ingress Controller will fail to start. + ## The Ingress Controller only processes resources that belong to its class - i.e. have the "ingressClassName" field resource equal to the class. + + ## The Ingress Controller processes all the resources that do not have the "ingressClassName" field for all versions of kubernetes. + ingressClass: nginx + + ## New Ingresses without an ingressClassName field specified will be assigned the class specified in `controller.ingressClass`. + setAsDefaultIngress: false + + ## Comma separated list of namespaces to watch for Ingress resources. By default the Ingress Controller watches all namespaces. Mutually exclusive with "controller.watchNamespaceLabel". + watchNamespace: "" + + ## Configures the Ingress Controller to watch only those namespaces with label foo=bar. By default the Ingress Controller watches all namespaces. Mutually exclusive with "controller.watchNamespace". + watchNamespaceLabel: "" + + ## Comma separated list of namespaces to watch for Secret resources. By default the Ingress Controller watches all namespaces. + watchSecretNamespace: "" + + ## Enable the custom resources. + enableCustomResources: true + + ## Enable preview policies. This parameter is deprecated. To enable OIDC Policies please use controller.enableOIDC instead. + enablePreviewPolicies: false + + ## Enable OIDC policies. + enableOIDC: false + + ## Include year in log header. This parameter will be removed in release 2.7 and the year will be included by default. + includeYear: false + + ## Enable TLS Passthrough on port 443. Requires controller.enableCustomResources. + enableTLSPassthrough: false + + ## Enable cert manager for Virtual Server resources. Requires controller.enableCustomResources. + enableCertManager: false + + ## Enable external DNS for Virtual Server resources. Requires controller.enableCustomResources. + enableExternalDNS: false + + globalConfiguration: + ## Creates the GlobalConfiguration custom resource. Requires controller.enableCustomResources. + create: false + + ## The spec of the GlobalConfiguration for defining the global configuration parameters of the Ingress Controller. + spec: {} + # listeners: + # - name: dns-udp + # port: 5353 + # protocol: UDP + # - name: dns-tcp + # port: 5353 + # protocol: TCP + + ## Enable custom NGINX configuration snippets in Ingress, VirtualServer, VirtualServerRoute and TransportServer resources. + enableSnippets: false + + ## Add a location based on the value of health-status-uri to the default server. The location responds with the 200 status code for any request. + ## Useful for external health-checking of the Ingress Controller. + healthStatus: false + + ## Sets the URI of health status location in the default server. Requires controller.healthStatus. + healthStatusURI: "/nginx-health" + + nginxStatus: + ## Enable the NGINX stub_status, or the NGINX Plus API. + enable: true + + ## Set the port where the NGINX stub_status or the NGINX Plus API is exposed. + port: 8080 + + ## Add IPv4 IP/CIDR blocks to the allow list for NGINX stub_status or the NGINX Plus API. Separate multiple IP/CIDR by commas. + allowCidrs: "127.0.0.1" + + service: + ## Creates a service to expose the Ingress Controller pods. + create: true + + ## The type of service to create for the Ingress Controller. + type: LoadBalancer + + ## The externalTrafficPolicy of the service. The value Local preserves the client source IP. + externalTrafficPolicy: Local + + ## The annotations of the Ingress Controller service. + annotations: {} + + ## The extra labels of the service. + extraLabels: {} + + ## The static IP address for the load balancer. Requires controller.service.type set to LoadBalancer. The cloud provider must support this feature. + loadBalancerIP: "" + + ## The list of external IPs for the Ingress Controller service. + externalIPs: [] + + ## The IP ranges (CIDR) that are allowed to access the load balancer. Requires controller.service.type set to LoadBalancer. The cloud provider must support this feature. + loadBalancerSourceRanges: [] + + ## The name of the service + ## Autogenerated if not set or set to "". + # name: nginx-ingress + + ## Whether to automatically allocate NodePorts (only for LoadBalancers). + # allocateLoadBalancerNodePorts: false + + ## Dual stack preference. + ## Valid values: SingleStack, PreferDualStack, RequireDualStack + # ipFamilyPolicy: SingleStack + + ## List of IP families assigned to this service. + ## Valid values: IPv4, IPv6 + # ipFamilies: + # - IPv6 + + httpPort: + ## Enables the HTTP port for the Ingress Controller service. + enable: true + + ## The HTTP port of the Ingress Controller service. + port: 80 + + ## The custom NodePort for the HTTP port. Requires controller.service.type set to NodePort. + # nodePort: 80 + + ## The HTTP port on the POD where the Ingress Controller service is running. + targetPort: 80 + + httpsPort: + ## Enables the HTTPS port for the Ingress Controller service. + enable: true + + ## The HTTPS port of the Ingress Controller service. + port: 443 + + ## The custom NodePort for the HTTPS port. Requires controller.service.type set to NodePort. + # nodePort: 443 + + ## The HTTPS port on the POD where the Ingress Controller service is running. + targetPort: 443 + + ## A list of custom ports to expose through the Ingress Controller service. Follows the conventional Kubernetes yaml syntax for service ports. + customPorts: [] + + serviceAccount: + ## The annotations of the service account of the Ingress Controller pods. + annotations: {} + + ## The name of the service account of the Ingress Controller pods. Used for RBAC. + ## Autogenerated if not set or set to "". + # name: nginx-ingress + + ## The name of the secret containing docker registry credentials. + ## Secret must exist in the same namespace as the helm release. + imagePullSecretName: "" + + serviceMonitor: + ## Creates a serviceMonitor to expose statistics on the kubernetes pods. + create: false + + ## The name of the serviceMonitor + ## Autogenerated if not set or set to "". + # name: nginx-ingress + + + ## Kubernetes object labels to attach to the serviceMonitor object. + labels: {} + + ## A set of labels to allow the selection of endpoints for the ServiceMonitor. + selectorMatchLabels: {} + + ## A list of endpoints allowed as part of this ServiceMonitor. + endpoints: [] + + reportIngressStatus: + ## Updates the address field in the status of Ingress resources with an external address of the Ingress Controller. + ## You must also specify the source of the external address either through an external service via controller.reportIngressStatus.externalService, + ## controller.reportIngressStatus.ingressLink or the external-status-address entry in the ConfigMap via controller.config.entries. + ## Note: controller.config.entries.external-status-address takes precedence over the others. + enable: true + + ## Specifies the name of the service with the type LoadBalancer through which the Ingress Controller is exposed externally. + ## The external address of the service is used when reporting the status of Ingress, VirtualServer and VirtualServerRoute resources. + ## controller.reportIngressStatus.enable must be set to true. + ## The default is autogenerated and matches the created service (see controller.service.create). + # externalService: nginx-ingress + + ## Specifies the name of the IngressLink resource, which exposes the Ingress Controller pods via a BIG-IP system. + ## The IP of the BIG-IP system is used when reporting the status of Ingress, VirtualServer and VirtualServerRoute resources. + ## controller.reportIngressStatus.enable must be set to true. + ingressLink: "" + + ## Enable Leader election to avoid multiple replicas of the controller reporting the status of Ingress resources. controller.reportIngressStatus.enable must be set to true. + enableLeaderElection: true + + ## Specifies the name of the ConfigMap, within the same namespace as the controller, used as the lock for leader election. controller.reportIngressStatus.enableLeaderElection must be set to true. + ## Autogenerated if not set or set to "". + # leaderElectionLockName: "nginx-ingress-leader-election" + + ## The annotations of the leader election configmap. + annotations: {} + + pod: + ## The annotations of the Ingress Controller pod. + annotations: {} + + ## The additional extra labels of the Ingress Controller pod. + extraLabels: {} + + ## The PriorityClass of the Ingress Controller pods. + # priorityClassName: "" + + readyStatus: + ## Enables readiness endpoint "/nginx-ready". The endpoint returns a success code when NGINX has loaded all the config after startup. + enable: true + + ## Set the port where the readiness endpoint is exposed. + port: 8081 + + ## The number of seconds after the Ingress Controller pod has started before readiness probes are initiated. + initialDelaySeconds: 0 + + ## Enable collection of latency metrics for upstreams. Requires prometheus.create. + enableLatencyMetrics: false + + ## Disable IPV6 listeners explicitly for nodes that do not support the IPV6 stack. + disableIPV6: false + +rbac: + ## Configures RBAC. + create: true + +prometheus: + ## Expose NGINX or NGINX Plus metrics in the Prometheus format. + create: true + + ## Configures the port to scrape the metrics. + port: 9113 + + ## Specifies the namespace/name of a Kubernetes TLS Secret which will be used to protect the Prometheus endpoint. + secret: "" + + ## Configures the HTTP scheme used. + scheme: http + +serviceInsight: + ## Expose NGINX Plus Service Insight endpoint. + create: false + + ## Configures the port to expose endpoint. + port: 9114 + + ## Specifies the namespace/name of a Kubernetes TLS Secret which will be used to protect the Service Insight endpoint. + secret: "" + + ## Configures the HTTP scheme used. + scheme: http + +nginxServiceMesh: + ## Enables integration with NGINX Service Mesh. + enable: false + + ## Enables NGINX Service Mesh workload to route egress traffic through the Ingress Controller. + ## Requires nginxServiceMesh.enable + enableEgress: false diff --git a/deployment/charts/quanxiang/Chart.lock b/deployment/charts/quanxiang/Chart.lock index 07fb494..d671292 100644 --- a/deployment/charts/quanxiang/Chart.lock +++ b/deployment/charts/quanxiang/Chart.lock @@ -1,7 +1,10 @@ dependencies: +- name: nginx-ingress + repository: file://../nginx-ingress + version: 0.16.1 - name: mysql repository: file://../mysql - version: 9.4.6 + version: 1.6.9 - name: redis-cluster repository: file://../redis-cluster version: 7.1.0 @@ -95,5 +98,8 @@ dependencies: - name: qxp-web-vendors repository: "" version: 0.1.0 -digest: sha256:8d1580b5818330eabbb5090eafb8fe3059d5901e8bda499e487f947556aa98aa -generated: "2023-01-12T15:13:07.654347+08:00" +- name: init-job + repository: "" + version: 0.1.0 +digest: sha256:ee4aa501e1a96c6355c3a9090506e1b19fd4bc9e459c9e259b7c8a8b4afc3e0f +generated: "2023-02-01T16:26:34.004025+08:00" diff --git a/deployment/charts/quanxiang/Chart.yaml b/deployment/charts/quanxiang/Chart.yaml index ef0aad8..7299f82 100644 --- a/deployment/charts/quanxiang/Chart.yaml +++ b/deployment/charts/quanxiang/Chart.yaml @@ -24,9 +24,13 @@ version: 0.1.0 appVersion: "1.16.0" -dependencies: +dependencies: + - name: nginx-ingress + version: 0.16.1 + repository: "file://../nginx-ingress" + condition: nginx-ingress.enabled - name: mysql - version: 9.4.6 + version: 1.6.9 repository: "file://../mysql" condition: mysql.enabled - name: redis-cluster @@ -41,10 +45,6 @@ dependencies: version: 5.0.33 repository: "file://../minio" condition: minio.enabled - - name: fluent-bit - version: 2.10.3 - repository: "file://../fluent-bit" - condition: fluent-bit.enabled - name: kafka version: 20.0.2 repository: "file://../kafka" @@ -108,4 +108,10 @@ dependencies: - name: qxp-web-portal version: "0.1.0" - name: qxp-web-vendors - version: "0.1.0" \ No newline at end of file + version: "0.1.0" + # init + - name: init-job + version: "0.1.0" + - name: fluent-bit + version: 2.10.3 + condition: fluent-bit.enabled \ No newline at end of file diff --git a/deployment/charts/quanxiang/charts/appcenter/templates/deployment.yaml b/deployment/charts/quanxiang/charts/appcenter/templates/deployment.yaml index 1da52f7..085ceb8 100644 --- a/deployment/charts/quanxiang/charts/appcenter/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/appcenter/templates/deployment.yaml @@ -41,7 +41,7 @@ spec: emptyDir: {} containers: - name: chaos - image: '{{ .Values.image.repo }}/chaos:{{ .Values.image.tag }}' + image: '{{ .Values.images.chaos.repository }}:{{ .Values.images.chaos.tag }}' ports: - name: chaos containerPort: 6666 @@ -57,7 +57,7 @@ spec: terminationMessagePolicy: File imagePullPolicy: IfNotPresent - name: container - image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' + image: '{{ .Values.images.appcenter.repository }}:{{ .Values.images.appcenter.tag }}' ports: - name: app-center containerPort: 80 diff --git a/deployment/charts/quanxiang/charts/appcenter/values.yaml b/deployment/charts/quanxiang/charts/appcenter/values.yaml index 3019483..be0832d 100644 --- a/deployment/charts/quanxiang/charts/appcenter/values.yaml +++ b/deployment/charts/quanxiang/charts/appcenter/values.yaml @@ -1,6 +1,10 @@ -image: - repository: quanxiang/appcenter - tag: v2.0.0 +images: + chaos: + repository: quanxiang/chaos + tag: v2.0.0 + appcenter: + repository: quanxiang/appcenter + tag: v2.0.0 imagePullSecrets: "" namespace: "" diff --git a/deployment/charts/quanxiang/charts/builder/templates/create-namespace.yaml b/deployment/charts/quanxiang/charts/builder/templates/create-namespace.yaml new file mode 100644 index 0000000..84666aa --- /dev/null +++ b/deployment/charts/quanxiang/charts/builder/templates/create-namespace.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Namespace +metadata: + finalizers: + - finalizers.kubesphere.io/namespaces + name: builder +spec: + finalizers: + - kubernetes +status: + phase: Active \ No newline at end of file diff --git a/deployment/charts/quanxiang/charts/elasticsearch-17.9.24.tgz b/deployment/charts/quanxiang/charts/elasticsearch-17.9.24.tgz index f003ad0c39a65426c12109558616002e73c06d01..8f85697725affc75bea12a49e46cb8413b2bf666 100644 GIT binary patch delta 84812 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
8EqD`a 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%0D;I?2yeJSR`Bu)aLClLK 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 diff --git a/deployment/charts/quanxiang/charts/fileserver/templates/ingress.yaml b/deployment/charts/quanxiang/charts/fileserver/templates/ingress.yaml index 45c2f42..36c3381 100644 --- a/deployment/charts/quanxiang/charts/fileserver/templates/ingress.yaml +++ b/deployment/charts/quanxiang/charts/fileserver/templates/ingress.yaml @@ -4,9 +4,9 @@ metadata: name: fileserver namespace: {{ .Release.Namespace }} annotations: - kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/proxy-body-size: 30m spec: + ingressClassName: {{ .Values.ingressClass }} # tls: # - hosts: # - '*.fs.quanxiang.dev' diff --git a/deployment/charts/quanxiang/charts/fileserver/values.yaml b/deployment/charts/quanxiang/charts/fileserver/values.yaml index 2fa022a..2d95500 100644 --- a/deployment/charts/quanxiang/charts/fileserver/values.yaml +++ b/deployment/charts/quanxiang/charts/fileserver/values.yaml @@ -7,11 +7,11 @@ mysql: {} redis: {} -storage: +storage: #如果global.minio.enabled为true 此处不需要改动,否则请根据您的minio的信息填写 type: minio protocol: http - endpendpoint: http://fs.example.com + endpoint: http://fs.example.com accessKey: Minio secretKey: Minio123456 location: us-east-1 diff --git a/deployment/charts/quanxiang/charts/fluent-bit-2.10.3.tgz b/deployment/charts/quanxiang/charts/fluent-bit-2.10.3.tgz index 4cd788e8bac8f84f0984fa094c104a76cc1622cb..c28d39494b66ea7383a4b0dc051d33e25f3a0eeb 100644 GIT binary patch delta 10512 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 S=l=u%0RR8bQ=q5-0098&(6RXd delta 10495 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 Be!Bnw diff --git a/deployment/charts/fluent-bit/Chart.yaml b/deployment/charts/quanxiang/charts/fluent-bit/Chart.yaml similarity index 100% rename from deployment/charts/fluent-bit/Chart.yaml rename to deployment/charts/quanxiang/charts/fluent-bit/Chart.yaml diff --git a/deployment/charts/fluent-bit/README.md b/deployment/charts/quanxiang/charts/fluent-bit/README.md similarity index 100% rename from deployment/charts/fluent-bit/README.md rename to deployment/charts/quanxiang/charts/fluent-bit/README.md diff --git a/deployment/charts/fluent-bit/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/fluent-bit/templates/_helpers.tpl similarity index 100% rename from deployment/charts/fluent-bit/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/fluent-bit/templates/_helpers.tpl diff --git a/deployment/charts/fluent-bit/templates/cluster-role.yaml b/deployment/charts/quanxiang/charts/fluent-bit/templates/cluster-role.yaml similarity index 100% rename from deployment/charts/fluent-bit/templates/cluster-role.yaml rename to deployment/charts/quanxiang/charts/fluent-bit/templates/cluster-role.yaml diff --git a/deployment/charts/fluent-bit/templates/cluster-rolebinding.yaml b/deployment/charts/quanxiang/charts/fluent-bit/templates/cluster-rolebinding.yaml similarity index 100% rename from deployment/charts/fluent-bit/templates/cluster-rolebinding.yaml rename to deployment/charts/quanxiang/charts/fluent-bit/templates/cluster-rolebinding.yaml diff --git a/deployment/charts/fluent-bit/templates/daemonset.yaml b/deployment/charts/quanxiang/charts/fluent-bit/templates/daemonset.yaml similarity index 98% rename from deployment/charts/fluent-bit/templates/daemonset.yaml rename to deployment/charts/quanxiang/charts/fluent-bit/templates/daemonset.yaml index 9025d5a..9fde430 100755 --- a/deployment/charts/fluent-bit/templates/daemonset.yaml +++ b/deployment/charts/quanxiang/charts/fluent-bit/templates/daemonset.yaml @@ -59,7 +59,7 @@ spec: {{- end }} containers: - name: fluent-bit - image: "{{ .Values.image.fluent_bit.repository }}:{{ .Values.image.fluent_bit.tag }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" imagePullPolicy: "{{ .Values.image.pullPolicy }}" env: {{- if .Values.backend.es.http_passwd_secret }} diff --git a/deployment/charts/fluent-bit/templates/fluent-bit-secret.yaml b/deployment/charts/quanxiang/charts/fluent-bit/templates/fluent-bit-secret.yaml similarity index 94% rename from deployment/charts/fluent-bit/templates/fluent-bit-secret.yaml rename to deployment/charts/quanxiang/charts/fluent-bit/templates/fluent-bit-secret.yaml index 1ed592b..bba2bd4 100755 --- a/deployment/charts/fluent-bit/templates/fluent-bit-secret.yaml +++ b/deployment/charts/quanxiang/charts/fluent-bit/templates/fluent-bit-secret.yaml @@ -62,8 +62,8 @@ stringData: [Output] Name es Match_Regex (?:kube|service)\.(.*) - Host {{ .Values.backend.es.host }} - Port {{ .Values.backend.es.port }} + Host {{ regexSplit ":" (first .Values.elastic.host | base) -1 | first }} + Port {{ regexSplit ":" (first .Values.elastic.host | base) -1 | last }} Logstash_Format true Logstash_Prefix builder-log Time_Key @timestamp diff --git a/deployment/charts/fluent-bit/templates/psp.yaml b/deployment/charts/quanxiang/charts/fluent-bit/templates/psp.yaml similarity index 100% rename from deployment/charts/fluent-bit/templates/psp.yaml rename to deployment/charts/quanxiang/charts/fluent-bit/templates/psp.yaml diff --git a/deployment/charts/fluent-bit/templates/secret.yaml b/deployment/charts/quanxiang/charts/fluent-bit/templates/secret.yaml similarity index 100% rename from deployment/charts/fluent-bit/templates/secret.yaml rename to deployment/charts/quanxiang/charts/fluent-bit/templates/secret.yaml diff --git a/deployment/charts/fluent-bit/templates/service.yaml b/deployment/charts/quanxiang/charts/fluent-bit/templates/service.yaml similarity index 100% rename from deployment/charts/fluent-bit/templates/service.yaml rename to deployment/charts/quanxiang/charts/fluent-bit/templates/service.yaml diff --git a/deployment/charts/fluent-bit/templates/serviceaccount.yaml b/deployment/charts/quanxiang/charts/fluent-bit/templates/serviceaccount.yaml similarity index 100% rename from deployment/charts/fluent-bit/templates/serviceaccount.yaml rename to deployment/charts/quanxiang/charts/fluent-bit/templates/serviceaccount.yaml diff --git a/deployment/charts/fluent-bit/templates/servicemonitor.yaml b/deployment/charts/quanxiang/charts/fluent-bit/templates/servicemonitor.yaml similarity index 100% rename from deployment/charts/fluent-bit/templates/servicemonitor.yaml rename to deployment/charts/quanxiang/charts/fluent-bit/templates/servicemonitor.yaml diff --git a/deployment/charts/fluent-bit/templates/tests/test-configmap.yaml b/deployment/charts/quanxiang/charts/fluent-bit/templates/tests/test-configmap.yaml similarity index 100% rename from deployment/charts/fluent-bit/templates/tests/test-configmap.yaml rename to deployment/charts/quanxiang/charts/fluent-bit/templates/tests/test-configmap.yaml diff --git a/deployment/charts/fluent-bit/templates/tests/test.yaml b/deployment/charts/quanxiang/charts/fluent-bit/templates/tests/test.yaml similarity index 100% rename from deployment/charts/fluent-bit/templates/tests/test.yaml rename to deployment/charts/quanxiang/charts/fluent-bit/templates/tests/test.yaml diff --git a/deployment/charts/fluent-bit/values.yaml b/deployment/charts/quanxiang/charts/fluent-bit/values.yaml similarity index 99% rename from deployment/charts/fluent-bit/values.yaml rename to deployment/charts/quanxiang/charts/fluent-bit/values.yaml index 8cb044a..da33740 100755 --- a/deployment/charts/fluent-bit/values.yaml +++ b/deployment/charts/quanxiang/charts/fluent-bit/values.yaml @@ -3,9 +3,8 @@ on_minikube: false namespace: builder image: - fluent_bit: - repository: fluent/fluent-bit - tag: 1.3.7 + repository: fluent/fluent-bit + tag: 1.3.7 pullPolicy: Always # If specified, use these secrets to access the image # pullSecrets: diff --git a/deployment/charts/quanxiang/charts/form/templates/configmap.yaml b/deployment/charts/quanxiang/charts/form/templates/configmap.yaml index fbfeeca..7c5a297 100644 --- a/deployment/charts/quanxiang/charts/form/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/form/templates/configmap.yaml @@ -60,7 +60,7 @@ data: polyInner: "http://polyapi:9090" structor: "localhost:8081" db_database: structor - db_host: '{{ .Values.mongo.hosts }}' + db_host: '{{ join "," .Values.mongo.hosts }}' db_password: {{ .Values.mongo.credential.password }} db_user_name: {{ .Values.mongo.credential.username }} permit.yml: |+ diff --git a/deployment/charts/mysql/charts/common/.helmignore b/deployment/charts/quanxiang/charts/init-job/.helmignore similarity index 100% rename from deployment/charts/mysql/charts/common/.helmignore rename to deployment/charts/quanxiang/charts/init-job/.helmignore diff --git a/deployment/charts/quanxiang/charts/init-job/Chart.yaml b/deployment/charts/quanxiang/charts/init-job/Chart.yaml new file mode 100644 index 0000000..bf1d3c1 --- /dev/null +++ b/deployment/charts/quanxiang/charts/init-job/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: init-job +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "2.0.0" diff --git a/deployment/charts/quanxiang/charts/init-job/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/init-job/templates/_helpers.tpl new file mode 100644 index 0000000..c6dc16d --- /dev/null +++ b/deployment/charts/quanxiang/charts/init-job/templates/_helpers.tpl @@ -0,0 +1,56 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "oauth2c.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 "oauth2c.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "oauth2c.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "oauth2c.labels" -}} +app.kubernetes.io/name: {{ include "oauth2c.name" . }} +helm.sh/chart: {{ include "oauth2c.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "oauth2c.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "oauth2c.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/deployment/charts/quanxiang/charts/init-job/templates/initdb_job.yaml b/deployment/charts/quanxiang/charts/init-job/templates/initdb_job.yaml new file mode 100644 index 0000000..3c0c362 --- /dev/null +++ b/deployment/charts/quanxiang/charts/init-job/templates/initdb_job.yaml @@ -0,0 +1,32 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: "init-job" + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" +spec: + template: + metadata: + name: "init-job" + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + spec: + restartPolicy: OnFailure + containers: + - name: initdb-job + image: {{ .Values.images.initdb.repository }}:{{ .Values.images.initdb.tag }} + imagePullPolicy: Always + env: + - name: DBTYPE + value: mysql + - name: DBHOST + value: {{ .Values.mysql.host }} + - name: DBUSER + value: {{ .Values.mysql.user }} + - name: DBPASSWORD + value: {{ .Values.mysql.password }} \ No newline at end of file diff --git a/deployment/charts/quanxiang/charts/init-job/values.yaml b/deployment/charts/quanxiang/charts/init-job/values.yaml new file mode 100644 index 0000000..d265f6b --- /dev/null +++ b/deployment/charts/quanxiang/charts/init-job/values.yaml @@ -0,0 +1,9 @@ +images: + initdb: + repository: docker.io/quanxiang/initdb + tag: latest +mysql: {} + +imagePullSecrets: "" +namespace: "" + diff --git a/deployment/charts/quanxiang/charts/kafka-20.0.2.tgz b/deployment/charts/quanxiang/charts/kafka-20.0.2.tgz index f1926f2a95165655fa1dad68e7ac2d61e1bbdf21..47b470ec00577693186bacbd0a1216c6771cb5c3 100644 GIT binary patch delta 104670 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 z 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 g95<9g(^b diff --git a/deployment/charts/quanxiang/charts/minio-5.0.33.tgz b/deployment/charts/quanxiang/charts/minio-5.0.33.tgz index fdcb9f57b5ba06d043deb18ed54f3677ce29d45f..6357ac5601c5d69680d6c024a89ba80893b3a1b9 100644 GIT binary patch delta 16796 zcmV)jK%u|cmI2e20g$g1-WNOjdygLN@9y*-?|sqR+1=ZD{E@_Oe-KiVL@b(Y1BpmD zm&_MHq5w!7hs-CcFWts9PcB1F0^vDRKBIk@N*RlOw>x8z$GF3M1y%WFH=%;3iBCnB z%_iNDPk8tF>DlRv*VjA=W+b`v;%MSr(z*IA`i=`i@`OyN;{qT3Mt$iPF9v%~L{!f> zbsW>Os+9FQVRD*|e>|Vhx_Wx)l2;jFA9_7+Z_oMELywOJ@QQ>f6(36gES~?nyAL1k zSLgr3N4?MU|301v58yoES1h1FK=C!O2;z|V6!=)PI8M|diR1ndLNcPEa2`CsIq>3& zCJ75@A37b!sW&A#h;$?*ld076T}~;C(=f#ELUobPP1UISf7IBppb{?A5ltd0sQ^Dr zm2855&j^d)dP);&fMo)bG*YreHE0SRW4V4-&kMOvLTq?IB?NR#(oh1MkqO<_|6CB1 zMS=cxo`&H$51BvrV8#QgdPxNh6oxDcl!T%RH`OIp=sN%jjk#cwCvzh!j2r-vWYUM1 zC(lj}2PfWce{Z+v_8z%A`xiT3yL-Ft&g1{%0K|EheK;MTae1ClK_ltV=&BE$vGCr! zjg^e)IJZJ1ACBS7AHt^kOM~~|0r(-Kk<2ml6RPkddHbW(zoc@@Q|Qk8(*+3o&DcJ4 zcfY>a-E;T%+`UH&vHdXAetTn3`+o4^Of?lJ+^0fRe^C?EPpHItal&U*PH8G&K$9!x z)8{-=NNIGZG@SjAj;Jrg@82|HJ`$H~w*RoJO1hW2sQcTSj1YU?j@Mg;v1VmKlPj7a z!)*ies0TulC?Fw^DDVUVCS<}!sic8|4UUW7YB6RU5;`sx!+`t3!=7F_(| zzDb#Xf2l;GbSEhbkfRjK{8F(Oxl zg=7@cKJ@gvL7GfxA9i}Z|J~Z*KoUvEX*i%#e>m2UqRSNj8kkDe&Qav?0OEx4gvq%Q zQ<6m!CCkdRFJxCvd!I)>jV1muW|K5QEvFmvz|Goo z^}_Iyb7?pe&T=ja5_Uxe5Gjd2)zX(BYdQMMIZe(`(Cn0|>0O1-BS~09lVWvGe<*GZ zL?8A`73kZTM1kfaRZ}nd!ug#?RH)V!0WO{m)SSV|TClStL!o9pjg%+}`Yai@a3OM9<7_-mY}D1QJ@p72TBv0ymy|AP!+hqLhT; zT>U{NG-v=x(H+6kbzagpDNCrZ(ecWSV>x?Xod0x`PYg}$py+u-$2_5#fAG9!VW^6Y zcp3!?Y$J0J0zDJ3c|E^zA6o}`pm&&n!o3cT*??N2|DX1&Z}J*SRhAq&Zl|eIr?YJY zPQZl1UqCRA$c*_)^SNSbhpJ{*)>;}F2(%t$gw2*xKTJna8iv~t@mgmnGJqLeK$YJH zf66(sk=0t!Gfg~z%}Klqe>{T2e+{;c){z9jqpY2$Kb&lAD|MPx?UE9m)puj!NHPXxk&u)GnLx({$o#EK7(_3oOsFO);(?q#B~hTYCDT?MrV|z!i5Bqa zO9>H??23kS5NWK|JOl$lQX{^@4cSV zb|X`)4|_X1fB)Jr$ulN!kWbHn1VN%mr&eD}-8e6{I+@O4e{f_1a*aBZpo_KHCZrzF zw~{6i30)S8Y|yiJr{{Vz0HEfyTfC2V6aplQxI~Ru^x@rm2S61pHfO41;U`3q=}RTR zziccLBYy#WY1Y-^Yj;Lv!hF$E56KDer6Tc{$el+S~u^ScA7SUER0-NnWEV3oSpQzmK1gmkq@%uPt7_OLw<|LdaJ02#XL08F`%IKpc7_*1p%p>N47 z4yiG30Vs7gpJT4kT=k+;s^H2{n2A_4i@)01Rue)=C&NwJa>4^3La<4s=7F=G&_E^> zG^BpMf7?~B2Ka_2$ZL{^G|71H)vpd2k6Faz96uVHgj&dP8*gtJB!?-vLNiZ_`*ih< zzLnd+#@Pfh+XYnRk~9LMRyc-QtpXDz{v_dP3}-JcPWpLUN4hB`GI4{PHOIzH%H{#; znw7eBO&1ghhvG*;6EtD;vNul^1o^9R>9=Eye=@|FWpF%->FUHhIIPTGr)0-b6^wy5 z=E1W>-J`ENmXsjd|eaLuI`WO@D5Z_2pt; zqU&Uz&ed;4JjDf!gvT@_^8xiaPT7ZQw$Oy}p!7O@;7J)xlrj~8K9f2;KYji3fq#>Izx#lL$=d(DK)Gf}})V$4qY0IeYLkp@IouQ3% zU#YV8rdk^gfQ*$IW(@g}kR%LMi$-IAe}aXYW{cK|&D(9;o*@&Zg5qX9q|ro9;TyCN z>czk`Y=vSIAXNfLc%#e-TaN zihP;w@aAo7)<+zj45^vdTpTg#hTvAs< z?Ec0_TaJ36(fyu}`V~dwc715uu3IR6Mt|CJ^p`?CZtPO*O^Bq|WZtM{+14q@^y-r+ zh&hX7Y0sxEkGSFKV9~-Hi7$6{fA{tuKGHj+A4O&)Bx=?I`CU!uQOHMNfZ2vQPcz%0 z+2U)9gKfzXTy5CRhRzQOn*m93GY87?1%_8`Y&9LaW1hGOhlBrLL=@Xh7n6j9Aq_Qy zM?Mu5s@3p)dNhE|r<_kh3P&MNgKVe2^=Xlx_`-1}zPK~YRdGL|0gcqke*(V=9%+j` zALlzX;`_MezobgCOnk*g-wPfY)_MSjP(BhWPB?loumG)o_~SIt8*eV|5^`!-{KuEi z@_l_Viadg|!vPp2d2LEZL^w`F?v~Qu@&ti;YV**H%;B0uGBX?*`_GZKS{qxq59dF5 zaKV8_Ld`>M^dWIfBe88+f1S`kpqWysq1Y?YniimKq!VBD;h(5Pebd=i`lhksXBH&& z{eS8+;tBCDM4%kF(F)k~4Q8F%@s@>79Hw&E6?w!wJT!_YuhT7~O1VE!J zmT=rDz!gcDHbo{hq*sRQ&#l7{4=$!uP~C*c?X58p*$$i+2V7c}f7}#!7KO)5=-#F@ z^Z-v4Y2aAhD=gbIuRe4hijG;{LrR2Fn#MH2RYhq(37yhNuq%qo>~e0_=(wdLKdnr8 zQ#lJA$5;W($#ByE;6C`oSW7a?xITzHW+F-PxbR6DOsKrwd1UTl)s1<8$84riW1_G3 z(+FqvTvi{v3~~c0f33+f$&vN56y)C5JDuuP;@*N`?JWsV4Xx zkI2#}KeO7#2D5&?G|J1DIU}V)34R05p)RJ7(p}nW=Ean1-xgy&ZN{Mnur^U`lNBMUSda(f8!YQmfp!f*FV4~`pk7i zv*j^>Ih9L~qnHpW72U`Cf8QRHkBHT&A|gPP_>A$wLcIguF^G4W|1X1W!9=Agc@ zNYdm=vG!h1n0MOJccC{yYP&16!T93nIOp-DNYuohkfKYaA1I-x{_R`qS7tbgiJYD% zbj;qGmDT47e+?o$A}+s2pP3_?$l8nSZ243BdNn=fxRK7{kVq=JXD=>J2A+H?@34<0 z{=fVCdk-uAfBU`N-Ov7i_wl@Y=b{npO@5$nX19mu9G(0`qywGoIHCjZ-#ccx)qCdr zXy%F$eI{ag2xJZ7`}glNgZY@Ng-mT{kIx2LsM+T-e{-HD*{Mh0dG`)79)*rxSTkS2 z4tVhXy{9^SNpX$#&NA_$K8P#dtN8t0@a!;1V}bqRw<#BL8|{Az#1ReowOZ$ABns4? z4`9aw?biY4FOFZI9X>xf*w{2)UZ9p-wO)bi<`NFt00TFKPNF{?R13lT_Z@IK>i$Xu z9dzD#e@xPuc-8yWn^8&BuEtZHyzgu&xOP3rpis~$b@`ek0c>Po;$hKBfH}@fN&=Yi zgaR4yRO%5mEvf-4PB)gChzwBKzpriJx{mWRPtBrqT^e;II>YjnC~-StS1iE2u_Tq)2|^Igiy zE~46uw>__N^MPWf(tOJtuHL_g!QR!rf@Ke33B{`2JI-N04mx(3&p!dVY5sC8SN9(xM ze}ku$qu+)?Fq-!rd;W_nf92^<;`m_ccsR}(mu7Q`N6u(+R3NBLDq8&r_&kln%w;>3 zRAgu7nf~pqGuQr^Z7>i$~{{MPP!t=vyYi_({<#C8W`@Y)n{4gG@K}oNUF;roZhde~s(& z(d(lZXWyPaeSLiT@}Of0$x6wN^Ze+b(@jN!fX&ous*AV*OJL(&sipTFJzqmXbuXo= zosuAXkj?xHuDyM=ZIXaLrT(QWLP}#7|AvtBSjmTL!ldQxUhzlEJ*3L*Zf?Ol2VijY z-HF;A>^K027Z)eb&o2fCJ@^Mae>;7CdU3G(cO>;8uBv-IAW}_2DbT)>kAxz#BI`9( zLjOw%2{lXSC7q*t;^EQJ$zX7>vFQ^D=KQ>yUjf*Hf5716=;g^pr9^%+U<>|Xy8KVw z<;9d{gu(-~{4NJk`vC>6cHUN?DFCQH<qT^ zt(dl%md?kwVKg_M$D2ByU@C|eWdex26FofN2{Kh+pwXJx78nMGNB5a6Mf!O!9#sk zXeez-T;e2g>^2*KK7aA-^yueOc0EJkKyyoXb2Nz?d0e^w)-5uvK#CMs$mG+}0= z25RJJwjgO-Pz>iFQW-Xf#v2KZ-rF`-=ETyXi$+F4sCWrKQ0<|v-J0}7$?SW&nS6mT zw{7x5;~JWHqO+l=gytNLvZmMunY#M8h`$Mc3_|OY1#h?PsVo^3S!Cr@6n@2kE-WC zk9YSz@Bi-OdH1gS6f&8bUbEnq2m^fDG}jn z3sv_k=cpQ_V4Q~G9NwfP)Yn!?93$MG^DnAf$MRD3p>R<8vQJV$LGW40Ur?V-Y1b3A z2|`y{f4vF9wR3Z%{Ta+TmRfv7O#Lm-IUR#J;n9s4?-ZelX5wwgk{beQFhz`vR>Bq* zFSoFlXSA%w(a6iR7FdbkYLUo(Y#{LcgVo2>f-|RsZl!$mmBU(kyEcGv!Xi0_&i@wf z{}!D}Yr5ZcxUB8(68Blds-}vG_@jmtht}|ke=dc#%+}$>GM!drY+CETP1q*5K?f}2 zQ|SC>2Rg4ix0p*W^~MN&X5u*Eal&w}Qq` znqQr74tBhKx3>-d-0>c}J%ulc$%utaGAcYZHBBqtQzkQ*O0@W|sH)Cvvd9n9py@PftF0-s0NqMh+r-Ua z=$Jn`3p-p+?em1kG|~2=8Ii!_EXq$yz@O)Kpr00M=kb3EB+9$Tyny)*9q7RO_iBp> z>&%=Op@(DcU(y6HJ`=p86DDLb2YrDS@D#pv{#0(;W&n4;a=xSC40gSpo$Q*se?C|( zt~{D6_vpEee&U&9a~8z`SX2%k;PaSnJEK&BY5eb~H|%;ly~3W9U8-kt8w7`I3K2D- z$7XRzv1imn+1N$a2>FEho^u!qzHLqpu%Q%BI|Pd+p}wbN^xcsBJ_oAc)|Z!=?w3Sn z@C#a5Gecjmg|-hhLaLIrtIQ3YKd_*Bar>ys7nNl_YilJK04-s~``RF$Kom)x!y|##GXyAVJzlM9Sohc1xo|ty0oL_d7 z+$?6;HvUNCNkRfzFYN|2q>{Q?)OPxSFYySI1~k|n(J@b`i*IqRG9J}UI;GUbrTgV))9B*zK3DNgDE;#C5;5^)B6K4K|&}!6)~D`_KbNcjo`G&m5PY z>Sa*g$#r$zSp80RnL{m_HC)4<`KOC7VrK=aSFsme#Lnt8U&SteF4Yxx>hgdF-6F_U zr?}2mxm8keGB*D4r4cFI7FV7(B7*al&U*PH8G!lTQ3rn}Ego|4#35Z>OUF@9y;L!iRM_4OvsX@k@ovwAbx(tDvrDiKuiO+PMA^KkXWjang9R=9sdow2luf3x(}#}x zu(S3q!fA>{s!4U8Q>waiC~p-$+WuhSh%Ft9kGN^5Udm_;6TM77S&hwW8uaI_%BS9{ zT=V2IV98=vM}^1Hg7`i)ZSrpQ$q&&e3!So}#Amre%Wpe>uHUJ=n)yJ28H=FcXPD4P z4Fd&9k_naIy1xk?f$K&}X$yG*?i=_9x`w*lnU8luZ7NqULqAyDkxn(2P!fi7JMC{m zXG*oy!6CNc;@JSzIbcGUf0MF=1{IWyGJEv;yBC9t*BXb)rp2hVQz_%}mawc%id@O- zce^cVr28#@X{7(JiriR`q1pnjJ$ytvOG8Ctu9vu-hkG%07;nRuFrp-($pycp5uPR% zgUVAGr?NJ6etWZc(x}z%2c47s`!`GGPea-Drcy%#A8S_q_6A%Et`F{S;3nYNg!^Z0 z;@ERZsxp6YhRAw0+4Rln!@uK5>mQ5{g+0e4SxK_keATSx9S8ShXuET2^94 zlL>_pms6;Sbwz`3DvV~B0Nkji+KHH;8jYA&u&zi)a5;7cH#N(hnoB->`7YN|;a!vm zOe|@CX2r_V*+v#c0Q%r%RlWS>cBbUQJJfEABKo~Y;&{7IT5F%pm-pLx2wrAGAo}p? zoxPK?+-bH!@1{KU&o+!g?q9x8wU3qBkELaj(rq+sB|HpilD$b;U;~k|VB5^WGH&mG zegFQ;($buLMdJSLZ!Lpon8NT4F3ZfXX};Ef%I&&J{=1694p3wrlqDFrZjj8~B#rWs zwV=}dw7`VPubWD?Aa#QrA~5H))dwH_MtxaTO#XP{bWvo4Zi@Q|87OPK^*KsX1$ zS~u4wlSom;HOr1}X;2z^1bS`agS|g)-nUoM1N>Fx>YwFVSN zp!v1ZmdH^>$+E|0Wn-SuHz~D3HweiSGHDM;CD`w@?gCo#=&@_)7BRJz#j%_84dzZ? zR>g#~vR|3}SskYw-KwET8xm!IkUF(=)mC7(W~B5iDER6s|J~kesm`K4KVO;s{M6Qe zJI~%-^|5UI->cpK-GBT!|M&eo4Y&SlcU0PRc~qbOl8duWy89v~Z&I443(r$XR4@G4 zep`+1TsJU!v`-`7TG2}Pei9M|hhaP=XXy-fdu`>5^ra?^LlqF)QLNE_e{3y4_Ll&% zV%`Wlze8KL*@>^{^u0cJH(f4VB%4FguNr>79E81m2c@A-0~J;RtrDQU9-_RZ=Y`|7 zniA2NWTGi4L_@NGqSktdx8;gx%j>YH>-CWT)I#)6{M6Tf?L&H>>;J>*`Hx!vKcD~K z%d^N#_t#w8n=PKJ2RvMVP;a$Rh?_jYZE3Y7otXb9OogP$>3Ih_oh{hJn+1(!x6GbZ zD=T?DrxePmrM{n)Hf`j;8!u$$U%|xp)2S))eR0`2unik5ZVDt@YeTzluxh^TckTKASCml;CC{f8dpQZele6BkNvJU4pDtx1=fj!S^x^I%*4&BnX(=q>ymY9r#r% zmp3{Utu~7WkmpNXU6-yV!>Z}hmDE>tUE0pjRrq>z4PvH$)M_MSk)+9$9qKlFvkF($ zYuA8X4GiHYB&HWS16EPF^m-M5TH2{WWnC&AR3bvH8pf~WB(5K{R%f?R^BLC=Bf0L2 zy;uQQBbH}H6In0L@?X^4SX=)kk#wAf;tt~eX3ygFf4BFjdjDtV;iKKp@qg~+Y4iUH zn2-q@rIH4J#sLU6e&-QAQd+yc5mztuf*`YU5fAF+5*mlhCzYZ>!mg+|r^%V>)hb^8 zP^zO-H>$!NwGea~jCz&D#j0g0i43XSJOCT{MLipi;-x92gNwf89I@jGY;KfeqpD9^ z*4w;=tsIneRPCnZHex=T(s71JOYsVxmP1ZU1*=4V29WKj(gsz{zXmp9bkk|8puR2H zINmBqthn;;O*88>ECrp4Zq{j5&N@XhfOHfxF+Jn*B_+Z9FbEPV1Qq%kcG>!R#v}S? zu|a+eLz?Tl%koOtOH@m$r-3Ol_^Uc7WUQsVng=o=l1}Ct+?uu9qQ;L{-YZwj%-+Fs z5|IgiozW-{F4Z|F2?;|QcAR>Sp_S%oCik(%EDh~t#9ArtEGqj7s@$?bW$T5AT|cZ@ zUiAK>mo-G5)2vJVOOehp_pg$=ycs8I_1*9;3`X7)A}B6Vosz#;XA3QPVoG)&J`(B7 zMm6t2$G=>?16_Vb;?^$eggR`Eaot?z24up2W`lG*W^bYMOVn9CZgjQtgz<#QdF~x* z%g)NDiVJ5$&4yejX7hJ90dE_;j|KHp1cOJCzOBc9Uzm@!Qn}!-B#jQmkAfzZHKyEG zUaB-l)Jt<6ZdqL{W>+4sP;*>VtI>H;6b;qnkrM1)J*GL!H;fa8)Jg;0{aJgU0~()K$W0Ta2f^lttvx;Ag@v@IHD64ys1@wpI~cxy8`isc|K9Vwcke)?BMZhIU2yn*`2M}Oym4{m zt5O?{v5ma^Yer_RA|CS@VG(x3#;`e&)h*P{mVvg|rr3z|EWj%jbLjC8r9L*aWRCvx zqh0k!6;BN7c9=}W5Lden{A%%7dlVHTjEenEB_?=w;@yOEQ`rUvELW@4Dd*#VcJUOs zTBaJ*dBffwwpFpDY=PW{waY6PHy?ESt)*(BYWeG0e(u&B{c45EmRM?YDl&U;*|i>s!$)kySO+XtO}BUU1>F-O#X>u z8j|^d`aB9mNpO}1$7?8EZ7`+@M znEtk*GHW5^*NlK)F%?07JvHsxA^97@x?QaN21dQpnE8zpVM&UwR8Ttt<_c-2{*=kJ z)sb!`)UBatt#UCf{*Md9qr9rwX!boJsWu%{}-(X9y zx!S0*0TY*}L7N>RKVz#NBS77tU|K2+rj{kS9CZO+LFF{JP)fTagaQ{xEy8mDeTIa*i%WM+ygx+}%E5!fW zsowwJeYo5ElRhx*e;rl)^ZdVu=Q)c`UpNQqahwMa;Oxc4>Cs7FPjvKKfhiF%<5x8J z59j~;fBzrnIHgKd$SH+a0gV&t>j_Pw0Qg97opb`?kVL<3;{Lzi?M|4SrX#!_pq830 zwk#e9Nn|QqK6d34WAmwLwFP{P&3{M3nTA1tb#f}ppp7Vve>8jwECLa|wn}@LN<}Zs zc_I@;8jf_!Ocb?W=`Yx^{@jRyo-`V=E!~5LhY6T+A!z_aLRL}L%JT8)I{)?NK<_~u zNB3CtGGmd)_?Bvkz;|pig>#yWc`_rBPvHfIZH0kWA2R=u0MaO+2^_}6pHg_nd>RP~ zSG!)%gHwd+fAIVid_IebWTTL3k$X5Jzw-zNd*FvW4Kk%9b1v}UN0E_Aa=jeDR6!J5 z5V2^S5FwM)muaFYJR?ftQwS+ZA|v`qIG4;9$Rs32k09g{%sz9?lgp5kKzNR$`^#6D zSC$_t%y>WxN(I~(p4n1!{MEGzyLzwrCT0F5rpt3De<=&-mItR1R2$ufIZweS5yYH_ zFiS(p;*f&Y^I?--(Fhc@Y>Ww6WQL>I0u~|H2^LL43OaQ}iIg<)9Oqj_7qzqoR1&7P zCjs}<8I80H3dA^&aK!|Z@M=nvRz$ZP=QNTD4^kf!+`87|IM%csaV~{SNG!}C1~d-& z9BuDvf4ah}AJP#`A}Xoj@_x5_nZH6VG^fsxD)jV}S97C)&G7YBrX;`&UC0#5=LyA3 zYJy2BN?^K<}lrpVa7Ted9Go#NR)Jd ze=xofxB+yW!$_A=f`*TQ7|JAR6zTdv8j%v6Sn^bp>7*GC7lb$c{0z(oTz@?EN5b1 zw$@lhCJ75@iGNh%+Yqb0vU=UvlmH@tBomZ=xa+Vn^A@12 z2$e@=I+)G#gV^o-==5MV&rc@d7f0{4n+SuBuxeEF3@I@+Trq;Z zBqR00lM0&X1*Y&<>}~-GLw+rQMQTw{ofZCMT27U_#l;ZUn(HYGDQF;Urq$D$2A<)Dn*3iG!-3`^eP(%|N)}IfbKLb=dq~cPwTf;r2 zY9Pv3j_B-k5VA|EWvK?o+``(kfVc9=z1KbuHX9P@7^a*B<>Ti6#^|SCUH# zbUdcM^c<%&tI^>V%TJj=y_JtMIE2D7(+pAkbmBub|2DR4!K8tyTl7$GteTFhErrIf9M6)rFE9!(M+Zl2(D_F($*634e&5{t>5DW$SE5crp8vs zjD`UWbC=Yi!eLmcI@A*l32T%pRURZkwBVXVm})mw2%qumj5x(0AR2WBC}wJ<$Hj}? zu~~t#`a<7rV2Vo;iq>Pj*c-t$tl{G6H32~sh6)1MSfTS}U_=Tce+0zZ37C%Np5q+Z zVz;XCmNR-H{FcsC60w#7Wp={0m^Ctw6?(Bj#c^)nJgW-Jo*Ou(I!oe%`b5u- zVVv$N>|-H`%f+&$E9->^=UfP8DVItv(x7SwnWiI8UrRtET++25>`F2b-7RljBwwC9 zJ2@Pjc)Pvbp4)rm?(AReeC_V-x;u~m&#(>2;?Bj=kyJ$?f7bUiKFxCj!_)B@m*)u; zG?I%)r$EwjP+5TFGbW^(X!*Vd5;|c*Ci5)W-^W0y36kNfU)P$GGryY6wx#+F9AQ*i z!>^xkY8G?SUyf=C$)&UM24?=X{U{^p`!rTUM%B?8+`T^QFCiI{GF*tF zjpW6%LB%+Czt1h!Nxo$FQ8ZmLL1Gk{&0%q5GX$Q%f6zK&8E$l`1xpI)u?DL~>_6Bunn6i=}IUq&druX@Y}# z&*-j?e`ML2dqLeB!29=n3|W=zunCQmjb~7IIes=I>ski#)2!u!C$o_md@ku6HXkY> zv)e<%An_$l#K)4UHYCHtA5ITXUktu|aeQ|6_~gG2pPxTFY0+U6lKJ7>>PT7#kDFgB zB=_$f$?NY)nEdyTGWz!9`Dyou$Ip*X&YpHhf9G#sj@i-A2J0VAejaKh^ZUQ6BZ*bC zmt@HO`&S2UVA!S7&%BuwGz<0>h$N~m3d<#1Pzy<{Vov2UEDKSiGroYUwq_sYDI>WI zY_0K_``xRLBvvV-m)}T`TJqj4Ry9b5UF|Htg7iToi=Yn6Y^hjGGZa6P37 ze>IUn#FVFDpp_fYO^S~rS`iYw?14sYZ`mMecC}+>EM6xA9akeVE6HWusYK%)^8lF0 zJW%c)*8*x!u~WF5UG0PqOXj3?OloRjtgt&rV%c*8!#rEba&6Q`aw&_KkVHQ%J#HDk zOyI2&L4!NRs1cIk-+R5@YU)4LnkW=r{_Sju!47t$U?Yb7_r4nY8AGT zT*3U2g}eLnnLiq{C^WTj0~dTU2`OL^wRWgI7ro90*yQ23V~iRh8OkJGZL8miq>gOV z+;pa(SFw^DOoj;(1zn!t;rd5>)>qIQE*7>S`J2rLXRYgitXh2Pe*9g(JkET zNUkYe+XD91+PKN@5cqhrF;jdLs`vYR7?Q=M&xRIm;3Xx&zY-?t3v?k)@C9BoyWi&q zh9yvzt919Jm z1Gv|EGD!L`++Qkw^hj0%d$v`&fpZ?@VL}V{*ZY6gAIX-mq4hSh^U3T&hUF1W1VlV? z6V9avXD=>J`ifVZmf!<(u!yd|m9BG7^|G&iz=XaCVk5b>#?un7v~dYZe}DzqEKJqU z+@E>P+cEMD;UqRlje)O=%*de_0K2E zF}W8W_^5UAQ(Fb#RwJ2*e`#N?@hBvpePZ_(xE;HOD>y2Ftqfc|8(4<|cYavD{8`^w zsT`U^4e@+(Xhl)dcM|T_n!dhTw=_88FmD>)!ibJ}Li3255UYxK z-4g4{d$GGdT<@fLLD<6k2#i5O74MQr-=G|tz~kqquV0=V z9{>FM_~h{T+3DHIFpGM+Hj|p1n1F>$FS96Le-+q{ZIA zsWzlaj%nPsffyHv+ybS~wlY+*&?EYK^Bq3x>#k)a+fVM`e+G0JeLnChpWJ6IDgf&RkcC;s#R1f3#e6+|tqU3{aTR}3pYHc^45a~~0Q?>1ClDNO| z(OvmZ-r|^Ge{Vu0y(aTz_JJEK_!tpD;FZ_|Q+Gi~HvRum$Vc575t1f4Jd3H=6?@(+ zSQGp8*|k7&iOaq1o?W1qhddJ583~IpBtRI_kHxa#wgnazxL)dkRqxMY}Xz7yT$?K;=@xzc@;;4ONe}$0xvmr@-PZPR|?5PT#2wq{` zy6|a;Kd564nv(9ACoa~#oxELN@RX2TBztVZQ^M}vWzYJ8XX1<1){y!V@|5#QNZ|;h zU1t6-w;R`qzs4)?Xe@=BV5Nu)QPzsq zXIBf!#VU_2c(@RsP~}-)@RUYUYcxN;eAei8_F^!|4zaSLAMIMiLb%sv*NEI&x}F^l zT7)T$<^7_La)rOBU{Nb{*~BdaLz>_?M%Q z{7&J??uW~l(eA37u3K0Jc5kuO8twkMwpv!w#AV0n11igB=m`z!6^SI+nHR4}!gP!f z7BvRK%VVMz!AiA7GbTdNz(mL^nz=TH`#E6rOiv-%W|Qwj=b#0JIuqvFWxDf6f8 zL;4Y(^?lG=kYtgh$(4O=?*;~bLSluOfBxjb=@=p|K~TAk_7H1)@<`|9I>3Y;@;?NU z8n_F6vNkLsX^z|0!7)3by9*R=gCv!HkSlbH-Of%TT?k_hNdNw~A2}rJ8kZ5tn8@il zCf#YTdjq-z3QiJ+8c&Sceb3MOx+@~-^MnQw-o$UkwT9#oPw4U4;Qo=lEs}U^fBuLr zx(s^*>N^`VU&&CMS_<94;91v1A&PY5eq2Wp^H-br&%iiGZxuQp_L?d1m_$!@d2Aw{ zXU^2!7A5b4k!%kgaRWcldEt6(A^eeWSwQZ!kaPxIU%09yOdunEMPWwb%vesND@)M| z=$J)C5Mz_B<``q}eV2}O2)`90e`ao35zBRWo5;~gc_M0w14Qqw>$y*mdxUiZm*Hf;1>r>#Q*B;#Dkp+)*9OXVoD7Sn=@e;wOB`n zft_CODZ~6 zNg{U)c6jVMF}{JXzPe!XS6}tP4p(j`YRNVs`wkAGg z!X`@+@gyUky?+{i4QnJ;_{`>0kXI%+dKu z+X&LZZcBobfh3ZS(@^b}Um<<8n?Q4_Cq0FH9{DtuqDw|XCPb?T>a9$87}7*^g=tk# zDY_4=X1BnKCnkBFH!-h>1(eVUM=YUhE-Y`WjV*FS{Pb3ajE2Mv8dX%f?_wFCpWWPVbB7mmO*VWFuBame?t3EesTFZiRMF{ zc?*uxB%zTE=P;(%b|$gxQd}IS6Bdb8v*r|RV6tb6?gM@1f9|Rd#a5nos~MgPZlY9Os1{GXAc!d%%%j~u)?m5EISZp~w zl_85TXAX@^4oqYD^x~yzGj*;y!B)YC2OW7G5;qEnAoB zO&q9tE38TTe+>+=fai@2YF~kiy4fmRO|EzQ)wc!9?S}J;HP++WRQS3;!gHMSLddSB z-xU+(ry{vJ-e1CtumXIZBviya3L3R)Tpf)1nTJfvw0wHT)45!HRx<>F8AQR^DW|rdg4E1P5a^tv31cY2IX~s-^UJ6sD^ZyZv zDu-DK^Okikr9cOFBRV!H+C`!{B$NmqX$u}kJuyVjfyazuYC%Nf0==S%*ZInEPV&ep zO$2Spe?e7n-s!ke9ven0xvXyITURDq(hBZ)aHJ(D8X_wYDb--XXASV42StKLvu#_4 zCG2oB2j@Q>y*@j9e$v1jXH+VN)luwg352*wW(kolmia5^7bmx!42D-ED}+-J*C)*a zOzkpFpyJZ>DR+)!UATZrA}&Rj1PXjL?OZecf4TwnLy}O}0N`pUALt7@?wqIYh)!6v zwe9GbtP+Ni-F2}@XmhlfK3S%Mn!ZX*A}EPi>;VCSmv*Vjkq_@baem4jL#F-F%t5=~@MH5!i{S zfAmIF60c0;GWibP{n9b<#((Mb)epfnhyT*)|I)G0`K9yzeaCVBr6hfs1ct8LAQLhk zGe18rLN#8?mfsW^QP28&uh+8^*TxC;naJ?pZW=gDcX(n#(jDlL(}|>2PYy;I#xj~_ zxx!rJo;2Y=@x%*NA8n;ne`+TJy(;PNf7WSN9Floq7UQXmQ>inCS~q5j43j72K*3dk zq|>odf-xV=4HPRet6zu<6Q@=&!t))n5F*I!E|D!AX80}M-6~l z6}Ic0_AU97v6(4kphB`TA7*o74>9juSIK%eWRfN%Jjk>~X9r9do&?X-8x=DO?HnIz|l=wHy%opo&$qEwI?Hn|y90p=#exeOd5};es76 z3&@Q3uU$KZ=_Q@R>9JZYhB+~^B1N!bwNMNvzIc5}=iYDVvgcwF-KR$bY(i&~Lm&#< zs`{8IXk$t+d9a=~OaM1Wq*i)4f4nZ=zB-ie(ieyL+d%v`Dbv+$Te-;A{-Z#krrBYpDs_ppNVweQ*>iBG+ zikZ}@S2VIr7%l5kZo|m4inkdsx({L=xH=E8oNv|A3ELKwO;m{*Ep9T6e{~M{sMx6) zmZ+sTTs%=_C|n^z&DYr+9J7!f#6(WJl6S2D0nOj@hyourIaN``CE3JWJTt9$4|>B= zj*W0o#;ZP2&xsH%4l0@8xA=I8`dC*dFHAy)m3z>-x8Bhy5@qRtGwNj&8d0^DmC``y z1hq@(WdY)8H<>3dU;JxufAaExN89y}$1k2Ao}L}(S))$@>NLy^n*k;eohkLb8DSzY zcmX~E!TuUclqyh2A$@A1;rHNsRHuTV9{bHuXF*q@ zQECI7l2)3qyDWn>5CMv^>FO&1ym4GIY(2LYCdO z%QvHXhvt0o`T65NCip)q9b%tZ=YV(7N3YlGJ=)*Le|x=N_1|7^clV2({k=zz_IG!B zkN3Xl?L6Fn`0xwp-9_iio>WMZe9`;hzN*OmNuC)GXy4XrK2O`v&*$g!^ZEI=c>ezY P00960Uom^j0Hy%|iB#5s delta 16802 zcmV)tK$pMMmI2w80g$g1!!LIB_Z~ieytlL8+yA1sv%9yu_mRYJe-1!MNfNPWvJE66 z;aoCb0Eq%1aU3$AsNQrd*F3olISGX4O!m)(R4o+dsO zT{fF^Lq6f%=ci|sb4lmwx9B@A2+0#Np^giD^c(f1Tf7+TIT2Ak zx9W^e>(DfKI`fUrb}LBqhs>XQFyjGLy`+K$3PTnJNz1lV>M~e}fZmx3}AKdym|m{fnKi-Mw9R=kfn>0OGvMKAeuvxI9m&ppkTFbk&E> zSa@&V#!A9;oLeE1565uk4`EaNrNMjf0Q`{ANah&&303%!y!}z?UsAc{DRgK4=>mlP zW^5n2yI)`I?z#JW?%tz?*nSvlzr8W2eLr|{rkaWqf9_Kus;CL-Csbm+IN>uYr!*BX zpve{U>2n?_q%^uy8qR)5N7R?$_iq|8ABjsg+keYox|5Uz$k7UbzSTE^co+msEy^SWl1$PWjigW%jfud2H3}mZk!0@B zw=yAz$wc(w)vs9n$2dU3%Y;Ze(L;7jC8zjXmsC`i^O*MGB@aUuP4sIAU`F2l z7?CT&LNW?zAA0)TAWbH;4?Dfy|8DJYAc>^oe>5CWDIDuZ(PfH%4NRqK=P2@c0CB>2 z!sJ|uDaoRVl4WJu7qTm-z0V_`#uEP+vq_quj?;~K;AZW)aYE?~HLb21i0u7QNQ5{; z6~xF#dx{WWvG^sOZyUbGKQ%+>zF^Ek3New>ZMfoLI-@Y-X(aKLno+9BD4mUHqC|AW ze*-FDlSkoPPaH)%-JZoj$fsM#8VJA-bdHl#!=QdK0TUWgMaw|R>^Kh?K;iYUxXmwH*EBoF-=|Xm(1~^sd6^kt8gle@U^r zClogZq7VC}3iNGEqCj(zs;QTJ;rz}cDpc!=02j{&YR=$fE!f$Sp-{7)MoN?feHfEa zC>itM0UTwEpjj)fnVhPLe?=tqE)B28=_q8r=O+@UnBKu?i8v(^l$zqfOPjBocM4sZ zP}bdh$5BYwtSs}IMP4dsqGx6|Z&$in0tqeQitb7Sfg4Xf5Qi`$ zQA)yauKpks8Z>~U=#F6NIxp#)lqFQy=y>JEv79|G&VM?}Cx#|=Q1m>ae`B7|On6?i zFjU1xJdFYcwvjmqfu0H2yq@2-q^(ECe3;a&&FY(Fj0|4;kXH+c=EDoYL>x6@Rq z)7drxCtyP1FCdslWX61@`CKuzKUK3UYb}io1X_qr9NQP$4WA5ON_NBA4Oh-oyC#J}9a zkGe!gNM8Y>B*OVm3eFLW0uP?d3sq7=$oZw7|9L;cuI=S?P~e{bq?SLS6k#?V(?ktk zsra^$l5=aiJ5VBwnUQ+T^CcY2qWv5N;7dw^e(9~Zk!ief1OO{FgP*+xkjBy(8bzp z6H*W8TS=3Mgf5FkHt5;A({sHU08n$!9fDGMr0H$0>9APzk{HfaX z(6?k3ht!z20F*kL&oS3%u6ofaRd8h}%tS1j#b0f0s|lf`li?<9IpF~iA=o5R^T1h8 zXdn{`e;QIh-|ebb1AN01Q{%1$1GxUjvtLpLM`ODjkmW9lEai-p_wPe zeY*Na-^y)Z<7|SM?Edg8bFEfArfiMj2wvGB_T^bai4L99CwpQ?lcz z3dX=2^Wa$_CmdW(u4tsBo+5~P*JHd z<7cO5Ck;?PS_A66%JP+2+##WFQYxe#(vZ!VTyqoW^I4oq>K3PKYTo9*v}IKHp#{~9 z&d^4>uT)ukQ>_gLK*mZ9Glu*~ND_vse?_CQKfyvxvqkH~=Iyp^&ya~yL2V?=sf0l-l#UV8nMGG19mRzATED>a=g_b0jw6H|-E95FBe?ToL ziioChMZQdTc=I+k>m!a%hE#^NerW?;R4pi1)Kes@*QpqbEfJL4>3=9rcAgOFPhoRL zE~%>_c7NleEl0i3=zh;f{fZ)TyFRpS*DVx3qd#pq`b(i6H+CuZCPdO}GH=wfZ0i(c zdi6;Z#GFO4wCB^7N8IpquxMe9f5ewNyLi5|wweyzF;85C!@>VAB8qLMi%CMl zkcOJUBcF;2)oS=YJsQB~Q_d$Lg`<$CLAKN1`n1STeBn3~U)&kys<@xfe}G16Wr5!W zkF>>}kMkWG@qOI#Us5GmCca{$?*)$xYdru%C?5$GCmekkSb$bP{BauSjW-u}2{|<^ z{^QGM`M$mwMIOP~;Q)-1yf&pHA{-|ocT4GSd4fPawRvbp=5S3SnHi3Z{pUzqt&J_* zhx4C2xZpq|q2{4B`j9xLf05X>tWIbk&`hb+Q0$dxO$*RA(uuG7@K02tzUgc$ebZR+ zGYgXX{y+5@@r3x7qmcYg;mK|`2W+CY7?+j2C>fVc)$VB5n+48j_s-`qE<|HSLv8jC z0-(_qOE~Tn;EE(nn<5h$(knyu=hk6}2NzQ+sBS{!_STq)YzNMZe*-S9N^S}~i^5|j zbZ=7{dVr^jG;pl$6_#z9S06eLMaL}fAtgd7O=Ftis-m=?gidKB*cHWPb~!g|bllRB zpH`;4show5W2^w?WVmSna36ePtRc%|4V>Z*M zG11riX@s+SE~^h-e+IdMl-6XKFvayLI!fAuoW)^Ut^OYh{L>mT3~ zedao%+42~`oXVxgQA~)Gitgk6zwZ^=jPZ-mntg5fK}~a`kUguJoXCudnE130Gu?_l zb5P${Bx!P`SbMK0%sXxAyU?2;wcQokV0>|Oob&inBx+($NYSOz50ubT|Mso*D>IzL zL{85WI%aRpf6D6fga#2F5trYi&&&}`WbH+Ew*0Amy_z0#+(>6}NF){Avlka915dt{ zci6`g|KI)ny{iB3es6dGv;W_HJn!DQXaswcALyIe?cq5`CqEJCKqotn=)n8;j#+N? zo;g37xne}0iC7*2S%dig{rk*dKIUp6Q`_0&vw;?BfA+b|oTo{4>d|-Jy@QNLp`#bp z%vZ1j9=w0=sSaOKT%*0SOuVQM;>!0bet#D{I}FlTV88fn%7xrU`=0`FL_>b9*7+HU z0=4G@*zrL7b-?+H3dPGf&YQT!qjin|c1620!Ya6((0efnvdBV#z+}{cv$aqWt*L ze>yJp;A!RPx1kV>=6%PW|KiGDdHRz$K3F;)j&sJP*<9k0GnyO~2x^mxRzCthPvbCi z*-j-D*_nB!e|zi9wSQ*Y3-|Q=n}4(UR>pk+-~5}*M78v?G48K6GrUTh)a+<$3pUl( zqPa|I)4HYFRZQK70gHSJXLeciKglfle|V&ZOR6^EtBu5RWxz1Wfj+d&w@RasR`?a| z655=SsR%aipISM)ho`Flzn;=Crpar)^?a>O@E^DzSfc+w+}(Rz(f=Rs?|r`icQ4O_ z|LBfb)D=@lPzf%Df4~Fy4iC%mk{{5wOoH)~qE|{tqhr~au#g6sZtOYPik(e=f7?+S z*XN_xM=#F4J$?H6`1IvL#}bm2k{##y(Ltx1iUa|hsnt{$aRZjX#=BBW?>lw{0LG~b<`4?P!`)b=H0e?#UOIL)H#xDL1A?LA@57&fA%iF!;kCuB#mD}Cif_DzU z;OM&(wL92x01huMPM)7%3=Vqme-C(e`uz0bVE6Ax>O)*r_j*92nuJoIeI*|WMP^0T zYpR6)ml6_cmd;B$NB6|Tqob3-;9z6ZClbv0c{jfTum%5s!O79flZ#4;{AR!w{KItl zpSsJ7Da{Cl2Wa_S4x;u03S8~Htw2)%P=Csyb7X2nld2xjhYd}Nez&`!e+{iCXUFF+ zPR}m-=J)xFmlqv`0|)o{^TV^_gN_>N_qFAGHrLRs)F^Cd^1y~Bg6?Fa=mmcdE)Fk# z92{)?7ye2k$wGJq8~QaIKo5R(00NH2sC+1g^lhBLM)n*26LyB!fFa2*op1FV$wszc z6#k`SO0u!)DR0A_NZ3IBe}G^Ap@unfv=*v?8%QuKPb*te^cz}`SHQVrskPY zWNgyi&}HBo=mzwv8>L|gyWjk6XRAP9a^SaNLmzLeKhk7E6*edOyr+VP z`mE4U+LE}$N#fXTHUNG8;@RoZ&j%a3>hB+4K0P_u*hBYC<4jOc3tg4eDE!Uzho!Xo zgf-2T!~|Frr|4*{e<)7h#v${W47CgIP-#R%C*wO^@c_-+C5B_;hVjfuS!PU}{pSXC zLy<2{(J#G@DQ3wR?J}&Fm9aS)A}kc9q#nU!25thbJLZW`tAlB^xsX8t*M$R#3hSkg$fR~fq%>#{2$WXIBi&r%*J>Rr__?BfAN2;Mn)q-Rl`kG)Iey$ z%tj5=$kA*;(zu`)&OxLyYz~b#5*od?ZLG|Rr9~HwjDk?{5`LiCLtVQy>4}or_jEJ) z0%303=STw z5BD5X&NVmIGQ*5E%DBZhyn5y7fJ1oFksFMxxDRlnbdt!2M|=1un+?+On7xILTQsIb zgsUx7-LIUZYLJ3)8isRtlaf$hTP1OfaC^?bsBRt0OVx+MLFvmrNd*PLXC;3@eKw_C zPt+y|e_dtuCJ5Kg&5`zJFy~lm@ewigw>;-`4CaJKH)6a~geIDaw;@Yz2&lmnF)~^S zTUfl@!d{-yvKmJtFVk9JC4#F(BKxs{!1oVUA5#m?oDRB`^3higYw7LU0LBT6+@%G)`HvDtPd+hcUz9c3i7Bb1G@YK{at$0tF%wQ_f3Oe+yq>(_krK_D0 zf0bmX!YK8A|L+gzuDHJCU4D&6p;tSLxo90)2YEP*Rzh1vR-^Jicf7yf7F!a>8CiE1 z&A+_l-H{@@;3H@|E$lKa#3*BZcz$XM3GX{1+7SHo*k?D#+Az;=%dN@+JNqAPg5A*! zIi`{(GlgT-cTO+NrRf2ya!AS7@2qVhe=QgDOt_$`I@&p4)+bTBx1J|0$3t?;i64<~wwt1MlCf zEh4Nlb7F)Zj=6tH6TtXP@RClLkjWhM1zNyU_}2MTxow*P-2KY=j)pVX^>%i$e{1gg zV70jNXs+C&=QjF@XO7KT6bE2YIe382W4i5(QVFK+SRkds23(p2=+x9Ih!u z)Px?J#UaI>Q4eKf7g;0Z6Xtu)VJP^vIXS?FQatStESiM+o|4gbL-P9^sDfKxUS_&q z5}Cm-Xl2a|eZ3aiKGX=QO4hD2LpN~3g6hTXqbgrimi4Tym0$q0oV|MolK)I*;lj!_ zKD_r1_1|~5|Euo*^>NFL#CI4Ba%ue6+WGIp-QAtf`~UlRv%wkk2Lb+*wjox3k3P@; z`*`Y}$<5J<^D~Vi%&#pBMrsCi^8g~>^U-beJGYYddu#Q!LNmy|QKbnlowBKlSz?%w{`)ZSICcZSs`9f8f-d`gHP@Q_n`-l?#%yV zpE)i))ytr~lk4ibvHG3tGKX3;Yq*9z^G_FF#Lfy-uVOE{h@I7GzKUIcT&gSX)a3yU zxz)SRW|v?eUb!hoh_ZQ6&${(D2Mb#IQ|}V4DVt1X zrw<+XVQ1}Kgwqs@RFmpFr&M+4P~IwhwEe-t5nDPIA92%Ay_C@yCVH8EvKpJ$H0aM; zl~27@x#r1bz>>wTjtY;X1@V1q+T`8plOLi{7CL1`iO+I{mfv=NT)$I!HS>W4GZsO? z&oH5p8U_lIBoivZb$=5)0@sa{(iZXr+&AzIbPaX8Gav7S+ElJyhJLWPBb{n4p(G6F zcG};B&Xj7YgF|e?#j^pbbHIcy|0ZP#4Js%ZW%lUxcP|DPuQd*pO^Z=!r&7k{En!)k z6uFYu?{-_#NcUTR(n$Yb6}hn>L$w85d-#ZUmWGPPTrY7u5BFm1Fy4kQVMIwnlM8-H zBRowk29>8WPGxQC{Pt$?q*1Hi4>~9N_ivWWpN6vQO{IngKGv-I?G3mTTp!%uz)irj z3HQ(1#Ifg+RAv6)43YJ0vgw=ChkwVB)=7BBm~kJoN$FI7%mJ@jx*mWFN|a^^-kDEl zT4e`0CDJ4cm@;7uId~7k=kZ+UxXLs%{kq8V$FC!rBown0_&URe?g85vvyj%HuxeLS zw5-I8CKC!HE~iit>xu^7R2a=L0k~03wG%NxH5xImU|o@p;BxE?Zfcf0HJ5z&@?EZ_ z!n-IBm{`((%!-wzvyCi@0QAAjs(Sg$?M%sqcc|SKMf7`*#PN2awAMbGFYmYY5WLKW zK=k3&J9{T(xzlWe-c5PxpKTb0+`oLGY9A}LA4|(5rQ2xON_ZI3Bzu#xzy=~^!M2%$ zW!&EX`u_cwrKLIhip2ff-&zLGFooe8T$Y(%(|oOemD_cd{C5?H9iYfMC`&MK-5{B} zNgCxNYeA*^X@LooUpJL(LFxuML}1Qos}DZ7vMznSdp69M1nz^3`Bg zd0WL(%iM8wb^Q~K@!femt!w{Fcu3bZ050?Y+<*AEYX5uK`<(ytUY?Z<8MnCwVy{-o zi1;3VN#&F$?04LV7a72eE$}4|>A$BjFuzEk1Qo+r!Pd!Br{h$_ME1o*#KzxOG#Oc+ zik)eunB_k;+WF6zNPk-D0X3|msrJSCP9e^rY;4kKcPyGt(3pU>KRu{FYl^jQt( zkCS-m5Axhb{*PD`sIgde8CWL&cY9U&zu((``<(yjUYfdx3;2|}EmNE&r zfN&0gwQjCWCXu3wYnC0|(x5c-2=v;-2YY|qyl=0h2l%VX)j!L#uKYIw!en4wZ3$TF z|Nr=5RsKJG^jZGj%X2UCKbP_q8S`%`=>J$!uQva${5y^P@Wl%8A9}r7{D*&l4Xz0%EmmQZ>7ZV-|uWYQjxO0eH)-37Gf(PP)pEn;dbi(@zG z8_b=)tcnR|Wxq1{vpP;Wx>ZAwHYCb_Aa!c#s;$6m%}D84Q1I1N{=2=`Qk_M8e!epM z`Khh{cAmYv>SNjZzgN5eyZ`ue{_p#F8gBj9?x?is@~A%lB^PI%boWI}-lQ~77oMk( zs9yN7{k9t2xo%+eXrD&DwW5{o{Ujs`4#Rj#&e9p|_S(u9=}S!-hbkbpqgbPV|JYi9 z>@NXi#k>)AeuuVfvlCy@>3ee-=L0hfElJUa|ptbx`Xgxt(C2W5!AzbZ$n#qdsx#EON z?(?t@7f0tgFJWNwR^p%W0K+;eMyeHw%*U;*@AlC8C&-8Wb@-}bxq{QoP;sD+Z}Q;YFiKP~J3TIYMq zo@M8MdprBp_>a4v<3HYi&$IIR->uK{){nw)OCN$i?a!tGX_2XXq+?J-P;eF;i+alCenA{@Dmc#3!MS0s9buz3P3IG)S$91l@2Nqp;is!S8@{94_d3UTd4Vr zYlx9t_r+eU0IU(qv!aQt7iak|YHqBp|B^^LPD61AaeuRC@%q2pdsMyuv-9xL?&tVF z_wuy){{&3PgpE>vNdw~m1RKBeh#o1e-QI|+mwG{vS-FS@^>PV~L*|o8(I8=0RGib~ zO!aCNFMlZ2(Wx6%;f`7eIt@m>%Hm?xGL=MzRBj%Cjr^jX4M*|Pl+wXPUviGv@dP$E z%CS+^r!DJk-ojQ6N;;}`Q*s+IpH1mFL!_m61y9Q%r=@~_RU!k(c2sGDs^(t<8!@`+ zv{g{wmTVkv6(m+%`S+%obsCm}PDMBCG%IJFA{jtB3YnOmaru&xV15_`2^E40eGR*8 zeLdq5{j=C0KZYUAb=_roCF~`tCDqfw6dC+g9TYOw(q7F2nGi`Qa}93I+HFzeM=bA^ zt7T^I;5mtZ$b`;lln0mUoRfrvAq_iDJ;%^W^E8wDSYwuk_A+9v6n7SteFar+S)j7@ zLd32g)+{f2|Iy1DBF|~orT(QzXPNs~NnPHI6SewocozmE?+FnUm#9w3U#zo*mOL>f zyAL0UbY`QP_n_lnuHJzzKO=E#7j;4%w#K+_E^`BaGGVhpIv%sP(D^0mtR6SI+Ihlw z!sI;n4z*=xYVt@4cCVgh%|z0$dS#1aXD};V zMzx)PmS`EQAwY&zwTKD~MOa|#J3zK0{T{!AwiH=sTCa2 z35)WgP0gWFlJUj7j!nvtz0|S<;RqB*~ z^KrX)id-#I4eGpMZx7q5SW>n?Zo}H;m5ZAXy8YHtHBq(vbuB-4YYy_IsQy7QY<|5; zRPPnja@WbyBnB%G)Zwb6XuBPt#ct2;YQZ4qyT2tgvz9%}o1^$zi^5qB^nQ4BbTSyc z{^8{3N~;(h^V?Fkxa`S2Ud;{o>ho!T(<~GZTCsCK@C8H|oE*J8x%dkcA@@OVle?F6 zz6~2!B(&{AG`eC5kJJvcjZ2kGxNJ%rU*rqGRvYpIK*7_cw;{Wt5f$P*;Uik6teO)~ z>xn%|$4FC3LOJcKR+{DB3X>LUM_YC)jnfvYhg~%!TLtk-0BKdI58qu}oDWui1<9_o z8c-(x#4!!Yd_a931)?N4OM~Mzl&&@y(}eM0c~hlw)kdT~23y`rxnQ*!45BW?#WbN} z%EMqmL)D_yrp7vm_bN?QiYXm@iTnY9|SYAt9jVOK=bADYxM)0{5h)wSY}llN=Eo%zxrT@_&@GUGDR z&(v?QCD>eTRM~)u%hRCEj*y?RRgV#%Zcs2S6$Vqwl3b3u0I#5Onp-GJyp};FGn!OS zXLByA1uLkX_f}ZGJ^NHKNY!W#rM`3*ad!M$Yqx5PSVp*iCsN&ium-L3Vd!NxiFiWq zyoVLyf9+K7|L;EB-Tjj|FztVxNBf`s|L)~^&Z5&7&VhOy=fMLwdvS4kbkf%o9sO2d zN(9XK6%GEw`Tzdk|HnB_sS*`(O5s&N;40Uu-Y-_dZUVGv-QoXRq2BT9cG4W9ywKt!*t z(jKN#(F=2)$OMswBi%9+MeSGm3wEqOH=>{?jfQMX_n_fn0;XI@8UT@yRaCXIe0;jj zf4w=-dl1LbJr=#pSmZIjrCK8J9h*$yoF-$Q%t+)@c!6PCVW8EA%zq?+Gzw?}hcWS| z6rM4kMuNiCuGjP66rq1QJU<1W&tf9kD5P5C9?r<`Jc7X<_#sb&Oex8n3q1HyWTcW@ zF9$GH5XBZmEE*?7$Rzb;nrI5oh?4jeLQ0azh<*~zCG!O`35n4o2)P8a&s_85GUOx> zp5y5L@)hQl<%bG09?*hP0r!Pxw$vPdb*;j#-fO-|nSY7t^4xz($^yFO!D$55Mz>+k zQ}9UyG3O!7(onKEq@eYD*rZo90tGD_V?q|0;V8C%MaXr6MU#+%P90GqB~3iX`Bu?I zEv*5SgsJUG!2NVaBkh6$F%BeLF~KCfn$n~d(JjY0jby@u)W-z3uJt&MHElg-|b%JuaFDPsWYSsJw4^s+$dl(e7%(^2{1z! zGKKPaLNSw?V3LXwn6Bfv|EuU6cD()n)GYagN}_mGK(>oh43*vdE@BemsCkYH0Ht;w zwzeZVBxz(Q!J;O{dQfAZEzfcP*ZEHnCtQsTk7$yyrfPpf(F12*I9KE;PX$kn6Nb^v zNQVNYOo*Hwrl>93kmh~I84iadBBss;C}M+&&8vtp3aJ)Fs*Dhpg9j4uRk03GKr(q)vO;bS0%GD#Xmx;~Ibqy+dRRHIHZ5$VAR@u%4@Re}XH zl5EUq0HZk&NF(+p)g2=b8OoS8J-sH7RPq^-%*Tv^LgsUN<%+fCwPT1f?JD zI&93m1t=>*J9(s=+b2lffMuWYC$k3f7(nFLiER3pWkarr650M}JD9 z2}RD8L$vp*7WPU~R%>g^QUzR8Yks@fDqlx0-)} z^emGp2}{DqbDSR|w(9bu7NA2R(wQoX++?wwYA#Sy*6w^8bWUl-RfTSlC*`V6VNXuNYv5TBR?KObUVjiJnAwqDUp-jtZr8!lvkReu3Z?i?hael-B zT1v8FtW#n3DKejrns2W3wFJ$)A-jJndVzImon?45lW7Hls~V=XwM2XaJPcmz_c#G^ z%0`B%vDGo7VF1J2C3UE97*?td^+ZF$8l_5=2T2euxF!*%+D#S0XZ$)NPB93GMx6nQ znOf;_@nUyuR-mlD(03b{;*x}-^;j?VMsN*lxOjR^KoEtYf&eyF=zJL%k%E5+0kL)h zrlYy%I7hbFt!ljGjGhR;r8AX8tffGiov% z>)+jT1H(>d)xHqP>=1S-qBVacB?pm?gk&<6g=I&zr>~bQv8?IJdf~x27lK*JrIL#@sMB!U963_^jbS((Gl1xN* z%Uc)8mnY9o4hJXRZg02e_8z%A`xiT3yL-Ft&g1_xY(uiRbFp+JRZ)M4_5F-b^W4Dj zbbQ9;c|rw^nEI=#hmn)qgq08>8!kgnSXZ^(!bSg%#ke5$%pRl*B85c?*5*;_o!)3 zW=Jlbm5AgYVp`r}PDX!|go@k)slCPxoL~_Fr@G2V0DrYdt?ncgi*=X0u#Kd?QH$@J zE8pbESw%m|a|6S7@7GfX43gG8++|4GA!a|tb9*GGTr5~W%1HV?jg^p5b+iU|uh05R zNQR^g7oun*dGTyeG0xrZbBlG7FWG$*O_xlN7)54tSRC05fhT`3w2oMYTOWqY0!T{T zE-9>#v~DaeYx*z`g_c{RLKe}oL0elRdCiJ=w@9uzl35^zrIl{rES-&Lq7=J`2UNhO zIkHt60gu8tZnw;#V&xd^R*QZ+B*Xocx2}jJMk89KijAZWVe|=++*uFFlKbgm=~^IZ z&az{g;Go_!y6b-gja>*9dLK3T(Q@ISwLe%JtFW{=J z*++TGNG=0gYdq$D_v#~wRm$k)Hxi_lymyOL4U%D3JIk*ieGthasKYYb9vrg-Z#~Un zobVZ3PicQbO(YO8lUaz;BI#5E=N@;)5W*NxP$%?}1Igl)@;2k5f5N;So zY%!Bsg>58PFn?s>?*4q{kH#ztO)cEO1)oep3Rpy~9cs@-uk!&mc{uJEqee)EGD%n4 z>Ng^(BO5h0ohj&5tRx4MVS+?KmnV3*{t=(`74(LSg>6XwD5$;a>zjvoOexXvmq>D_ z$h3dLz4k~}qqZ(M@ENe*aU|=A`XOPnyToHL+%SCD>pf+w8<$(Nkyo40BT1rSJ9+-o z5n6S03->ybYf9I)fW5UgZt^<>KHhB16d#4^{XQRtWO3=Up@kcGNlEapgh~1WU5FEW zf!ECL_ql;#36$k(T|+?VHo=3z)PP`6w;+F4){W;-eWJ24dK`ZgB-fO#xqrqAJ_B^7 zu*z!W_iFC|?zNr_l0FRgmx>=flGVVTZIy1|oCkTB(8B%o{-5)cbl?5iIzp)Z2iNUp8%w8SfITta^m zU_mwuQ}r|VAI_a6KK^q9!<}_^A#H(Ght;Na+|*Bx<%c6VZp5$=$+|$*)}N1!_xecM zA#0Xwnlbc+IZH?D6%Wkq7Q8NYZ_oN$tt<%63a46!Sp=P2vVIy=*GJL{#jJ851JHnQSw2;cE*;A2T6V-FbfWTv$O#Pi;s4@G~n9O7?S zZu(zJt1ggIWd-o`9@T&hl68Fs7DwD1+D$)a5u2qmrLHMu5Chhj3RL9EoS^_W_m>3= zXhMUm;5ZGLALMbcDQilfG*j344ngEdjS4U)^FWDc{Y zOM)k_cmI;-28NGTRL`4{Y?psLe`dk6Fu3Tj)O4%h*)#{uBMLhLV~|kAyCl*#D2FES z`1$GUmnVnEKfgXcIXr%LdUi6*qMoje2(*koAvVzaDDcpc$noL>`Vb9e^oOp&!*%(NOVZQZI*Ztkq zT9aLkXVD6mp7IN6riy*S{Bb8?4U)AT?a3w8!}vWPEpm@2`JmfYkW8*x+s!9L`cv3c zZM&Kz?r(f_SN@Z?I3|DCn-EE_$$Xi8;Km9*Mg$OeCHBD7T@aE@|9=$nQFlg!q=^pC zVk&mUo;M5D#D0BtEs$K|a&Nn57wF|7k3@Dx!XgX_5Qg+)vF!Se_63s0spG_Cd#|%= z_9eR!G1#+1(Pcg%AOHCfc3tAAeUk-Rx}vgsvic zs)8qiS6H_$d>Y~p>X?J3q&wz`i*;`&Z`T(*B_tQg9$WB~u)BBJv%cV&_+qs+q`rha z<$MxSIKpU`ng7e}#&zPaaSLJnk+hJU_)6@2FL7!0yQtgPrqyB4t!?zP!9 zBDa>VXNQ9pVTz>|2-Aps$d#`3+0{aFb#}GTE3@l});NC_!|R^^bbFkdkX(~pN4vM) zYCR$TU=S%JLa{LPL5*A_;cp z#Ve999V3KAje+p;n5adtQf<+Ui4Zg}5%P*=u8rY-4j4VtQ%JViG0Bq#-qlEAY){EE7rw&GGbq(Zo5*>>XH-sUDuBl{A?p2IJnOS-3z8(a z=VZPiB^!_N#@PNu?j;3f*G2vy(^{!dL^+zyIw=4#~R4 zWkfP2a(a$QciQXTfG&Z8lZ2th6Qg$D^RvG0ib(oAp+ST<@mq1NA$i0TdVDsxe`Ifq zB;J3TKcb5+!`^`U&c@7FG8CtlLU%BD)-_RxA|1IO*HOg$)h7NkFwW6ih0ce)W(qte z(UV;sn~3L`Gj+E`$@^d=+e1g(zz=j@xL#WbeFEu*rcmD#u$9xr6V1}Z^eIznOj!GavdId4wU%Q0vs#S^iW6Nzohd6 z)E8fE=YRe>%!41HMrH@?AA0aDPk_E9vpA&NYos&y#Q_uXzj{0IVCRChhW5XhQbWV$ zOc+Kj){$Xgr`LPRF#i|kIjeg1dyaD$;st9-!?~3tCXYm`gVM8*YV9nGGA%3`nh1Z2 zCJ29HHi%o2$Q^?n9=lGAZ{Vx1E?E54SADRp$URf>tx@rB`a-3r;43JI}WrZj% zrJBj}qp0m;iO?*nW^LJ4Dyiun6G`NiYc=mY`Omg?*uabfcx6zBI#*n42PRuI2&w^9 z_rQj&i4U2u$x=nFikarfeI0KL$zp#6WREK0xR~*K3aSHSI3Q}n>L_TSgG^(a( zpl@T$M`d00wQ?kl=Abra(F8B#V~ntED}s9_UvSTr`51uYl7y=JokwP{5NCgstE!1S zcTGlx+YiV#f^@LklHg<@iKOE+RJ-L@NFVJc(46W?Pa&U2K8>a5l97-J(dvPED-#}u zG!b24S`}1^?gOjYEwJK=NnYno%qwC6C3M0OOX!*l%iC&WiyYB-`F9&1XzFg3g7hofLnAG)y2nBg&Uym?cGl8HrMTk5H$wFe$DZb4*xBdX95; zIDn_x+*FpIYLLn~vYaA2m2GWYD*0M0s4yVTJVp+w9wyRC|Q zj&L*D; z7Y%sJ)}?wA2ddr*Ytnyy14As}c_V|`SKy*)n3!ZNYN8;k;sv^|&?_zAljP z9Ot|cva9KL#YFk3NUo0em+&I20G}rb6)}&3My(oG2cv%GA=C2sWtbZ+pPun_E|^ck zJfR}FA}qu;hPCFj)7wF9AHL?vC0e6&5|@N1tpT;*A)Uo?e$0Q8;dXX8yalzzdDyC3 zl+qRTW~IDy7(v#19+g4Bm?c8yPQ$pa5xfP+gt@$#r8qr9JzA06IBpUFAy-S9F%zGc z!j$R!e?+3nVOGMtWt~eY(81k^jtz=-k!TJHC4xuVf`?I04AFDoF{7AT5Yf0muV~_R zzH*$CJaS4CL0f-vP!*haI&PH5hS5qctK0e3mC2U0f;%1@X$gvk$O=SCHCXUj1H9)! zk)Y9R+ty(TJKW5{`Au5q$!#Zt;T6dW z;S|L6NwWY`yG#?PxHNsrog-NnE?|;~OVK5P0$)u#*GzxEZb1EzB-AwkxEjg_`ht!- z=czlQ6Bcc4J31z-gkfZNT`Us$@?a9E+FHhr_YnT3{&}SL<+D^st<}pk!DOvvd`9`T zZ%5&6A~zn>Xl@-o6yCIYchc8#1XX+*jd|izo9M4e7`}#>2YEWYys5r}1`0(tU*>MQ zR)Jgub|QZ&y%CkfD-*d)zJqtabWFVQUpjsDLvYREzjXS)bS!j!>AZj6ah!iCNna*` zq3brtgp9|`&yR~xjn}f}H$_I&v;N-e_3Xs8aYB72GW@rj1`g95o|uqy2YTdmB5Bo= zgHeXDjHX$xFc-NeO*l|I@j}%{TPf9_+KE7~O8S4hb=nn&WL}uXcq-#m>Wrb*jhQ0D z02v%9IHylTrO+c5m`+NSHiuHQG-M+2ZTPTV%2O5EcWXrpBqW2+V@jm z7W`tkV8_b>GUNSg*G^%2N#}5StQL!5PK>Nb5v*7(6vK%xUSHC=_ZzzGxtK)v>Cph2 z(Ane=h{Cq2K4uEqm=a7LtfvhVz|9e#uB9gIswK03KUXEpPFd+J@_8gsURqMA9?@$>G0+0;ge@4sK9=6@K3bI zelyfr(3NPE+CZnIm1gnmB33CI_M#!QbD=l$Ytg99wxw%crk`buYub6$`xV_&4)pJT zoo(yAQNJP{(bDTQnb6ifo}F3K7>&wVU#t^9G|y?`ySM~pz5Hq}X1aNBM(gfgj_|hD ze9=m-WK(9Z3TZTvQ}_mYxM&rPW)~q{IMVh(W7$#|-UR$QQZn--Bn%_V@AMUawdEx7XX<{bFZ- z@8RRedprBR{V#eu5BDEF{sMY;(fP6`6_O-h^gg(+Dsq34XT}5CxAmIO)AsZ8`T6{O Ve*P_<|33f#|Nj|8{ty7B0RV-j4M6|^ diff --git a/deployment/charts/quanxiang/charts/mongodb-13.6.2.tgz b/deployment/charts/quanxiang/charts/mongodb-13.6.2.tgz index c568807eeceabb94ac7b4549c3dda697a9ab2641..3d4c932c35d141b88ff6d5f5b23022d593e74b8c 100644 GIT binary patch delta 70368 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%0D* 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 XpU3B`eE$Cc00960n3-Zv0KNwR2?G1p delta 70385 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�W1jaRAt)Rc#KJ2O2i^esU<4BguHj9T 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

2f~2{$yGZO$_0e#+HF?6KiUi> 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%0D(soaXL8O*}kND+#qRy3dymk_|7))(IxL(7yXFO6 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 diff --git a/deployment/charts/quanxiang/charts/nginx-ingress-0.16.1.tgz b/deployment/charts/quanxiang/charts/nginx-ingress-0.16.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..427034486c6877dba0a5f54357f4b5b32257554f GIT binary patch literal 40188 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�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 z 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 HL5BN3qC2W- literal 0 HcmV?d00001 diff --git a/deployment/charts/quanxiang/charts/polyapi/templates/deployment.yaml b/deployment/charts/quanxiang/charts/polyapi/templates/deployment.yaml index 615daf5..8176ded 100644 --- a/deployment/charts/quanxiang/charts/polyapi/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/polyapi/templates/deployment.yaml @@ -74,6 +74,14 @@ spec: - name: {{ .Values.imagePullSecrets }} affinity: {} schedulerName: default-scheduler + {{ if .Values.hostAliases.enabled }} + hostAliases: + - ip: {{ .Values.hostAliases.loadBalancerIP }} + hostnames: + {{- range .Values.hostAliases.hostnames }} + - {{ . | quote }} + {{- end }} + {{ end }} strategy: type: RollingUpdate rollingUpdate: diff --git a/deployment/charts/quanxiang/charts/polyapi/templates/ingress.yaml b/deployment/charts/quanxiang/charts/polyapi/templates/ingress.yaml index c5d31bb..90ea451 100644 --- a/deployment/charts/quanxiang/charts/polyapi/templates/ingress.yaml +++ b/deployment/charts/quanxiang/charts/polyapi/templates/ingress.yaml @@ -4,9 +4,9 @@ metadata: name: polyapi-qxp namespace: {{ .Release.Namespace }} annotations: - kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/proxy-body-size: 30m spec: + ingressClassName: {{ .Values.ingressClass }} rules: {{- range .Values.ingress.hosts }} - host: {{ .host | quote }} diff --git a/deployment/charts/quanxiang/charts/polygate/templates/ingress.yaml b/deployment/charts/quanxiang/charts/polygate/templates/ingress.yaml index 52cf5fe..fd3fc8f 100644 --- a/deployment/charts/quanxiang/charts/polygate/templates/ingress.yaml +++ b/deployment/charts/quanxiang/charts/polygate/templates/ingress.yaml @@ -6,9 +6,9 @@ metadata: labels: app.kubernetes.io/version: v1 annotations: - kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/proxy-body-size: 30m spec: + ingressClassName: {{ .Values.ingressClass }} rules: {{- range .Values.ingress.hosts }} - host: {{ .host | quote }} diff --git a/deployment/charts/quanxiang/charts/qxp-web-home/templates/ingress.yaml b/deployment/charts/quanxiang/charts/qxp-web-home/templates/ingress.yaml new file mode 100644 index 0000000..b0d16dc --- /dev/null +++ b/deployment/charts/quanxiang/charts/qxp-web-home/templates/ingress.yaml @@ -0,0 +1,29 @@ +kind: Ingress +apiVersion: networking.k8s.io/v1 +metadata: + name: qxp-home + namespace: {{ .Values.namespace }} + labels: + app.kubernetes.io/version: v1 + annotations: + nginx.ingress.kubernetes.io/proxy-body-size: 30m +spec: + ingressClassName: {{ .Values.ingressClass }} + rules: + - host: {{ or .Values.global.home_hostname .Values.home_hostname }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: qxp-web-home + port: + number: 80 + - path: /dist + pathType: Prefix + backend: + service: + name: qxp-web-nginx + port: + number: 80 \ No newline at end of file diff --git a/deployment/charts/quanxiang/charts/qxp-web-portal/templates/ingress.yml b/deployment/charts/quanxiang/charts/qxp-web-portal/templates/ingress.yml index 76c9669..398c1ee 100644 --- a/deployment/charts/quanxiang/charts/qxp-web-portal/templates/ingress.yml +++ b/deployment/charts/quanxiang/charts/qxp-web-portal/templates/ingress.yml @@ -7,8 +7,8 @@ metadata: app.kubernetes.io/version: v1 annotations: nginx.ingress.kubernetes.io/proxy-body-size: 30m - kubernetes.io/ingress.class: nginx spec: + ingressClassName: {{ .Values.ingressClass }} rules: - host: {{ or .Values.global.portal_hostname .Values.portal_hostname }} http: @@ -20,7 +20,7 @@ spec: name: qxp-web-portal port: number: 80 - - path: / + - path: /dist pathType: Prefix backend: service: diff --git a/deployment/charts/quanxiang/charts/qxp-web-vendors/templates/ingress.yml b/deployment/charts/quanxiang/charts/qxp-web-vendors/templates/ingress.yml index 3f725fa..e7bbf27 100644 --- a/deployment/charts/quanxiang/charts/qxp-web-vendors/templates/ingress.yml +++ b/deployment/charts/quanxiang/charts/qxp-web-vendors/templates/ingress.yml @@ -7,8 +7,8 @@ metadata: app.kubernetes.io/version: v1 annotations: nginx.ingress.kubernetes.io/proxy-body-size: 30m - kubernetes.io/ingress.class: nginx spec: + ingressClassName: {{ .Values.ingressClass }} rules: - host: {{ or .Values.global.vendor.hostname .Values.vendor.hostname }} http: diff --git a/deployment/charts/quanxiang/charts/redis-cluster-7.1.0.tgz b/deployment/charts/quanxiang/charts/redis-cluster-7.1.0.tgz index b0f6a4dc1b5a9c7cfc943de5ee5570cd92d68253..ecf18543ddad4a164c5ba7388577917b703c01a9 100644 GIT binary patch delta 75974 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 diff --git a/deployment/charts/quanxiang/charts/serving/templates/create-namespace.yaml b/deployment/charts/quanxiang/charts/serving/templates/create-namespace.yaml new file mode 100644 index 0000000..ad1bff4 --- /dev/null +++ b/deployment/charts/quanxiang/charts/serving/templates/create-namespace.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Namespace +metadata: + finalizers: + - finalizers.kubesphere.io/namespaces + name: serving +spec: + finalizers: + - kubernetes +status: + phase: Active \ No newline at end of file diff --git a/deployment/charts/quanxiang/charts/web-process/templates/deployment.yaml b/deployment/charts/quanxiang/charts/web-process/templates/deployment.yaml index 0bcce0b..fd9ea9e 100644 --- a/deployment/charts/quanxiang/charts/web-process/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/web-process/templates/deployment.yaml @@ -35,7 +35,7 @@ spec: sidecar.istio.io/inject: 'false' spec: containers: - - name: container-kudq8k + - name: container image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' command: - ./web-processors @@ -61,10 +61,12 @@ spec: affinity: {} schedulerName: default-scheduler {{- if .Values.hostAliases.enabled }} - hostAliases: - - hostnames: - - qxp-static.fs.{{ .Values.global.domain }} - ip: {{ .Values.hostAliases.ip }} + hostAliases: + - ip: {{ .Values.hostAliases.loadBalancerIP }} + hostnames: + {{- range .Values.hostAliases.hostnames }} + - {{ . | quote }} + {{- end }} {{- end }} strategy: type: RollingUpdate diff --git a/deployment/charts/quanxiang/values.yaml b/deployment/charts/quanxiang/values.yaml index 119c51b..865bb12 100644 --- a/deployment/charts/quanxiang/values.yaml +++ b/deployment/charts/quanxiang/values.yaml @@ -11,31 +11,52 @@ global: home_hostname: home.lijy.me # 用户端访问地址 portal_hostname: portal.lijy.me # 管理端访问地址 vendor: - protocol: http + protocol: http # 前端渲染配置访问协议。 hostname: vendors.lijy.me # 前端渲染配置访问地址。 - port: 80 # 前端渲染配置端口。 + port: 80 # 前端渲染配置端口。 faas: - enabled: true # 是否安装faas。 + enabled: true # 是否安装faas。 + loadBalancer: &lb # DONNOT CHAGE &lbIP, 不要修改 &lbIP + loadBalancerIP: '192.168.208.193' # 此处填写LB的可用地址,如果使用了MetalLB,在定义的IP pool里的可用地址。 + ingress: &ingressClass + ingressClass: nginx + + +hostAliases: &hostAliases + enabled: true # 没有可用的DNS服务做解析时,需要将此处设置为true,配置容器内hosts文件。 + <<: *lb # DONNOT CHAGE THIS LINE, 不要修改此行 + hostnames: + - 'qxp-static.fs.lijy.me' + - 'default.fs.lijy.me' mysql: enabled: true fullnameOverride: mysql - internal: &mysql + internal: &mysql # DONNOT CHAGE THIS LINE, 不要修改此行 host: mysql:3306 user: root password: qxp1234 log: true - auth: - rootPassword: qxp1234 - user: root - password: qxp1234 + mysqlRootPassword: qxp1234 + mysqlUser: root + mysqlPassword: qxp1234 + persistence: + size: 8Gi + +nginx-ingress: + enabled: false + fullnameOverride: ingress-nginx + controller: + <<: *ingressClass + service: + <<: *lb # DONNOT CHAGE THIS LINE, 不要修改此行 redis-cluster: enabled: true fullnameOverride: redis-cluster password: qxp1234 - internal: &redis + internal: &redis # DONNOT CHAGE THIS LINE, 不要修改此行 addrs: - redis-cluster-0.redis-cluster-headless:6379 - redis-cluster-1.redis-cluster-headless:6379 @@ -45,8 +66,8 @@ redis-cluster: elasticsearch: enabled: true fullnameOverride: elasticsearch - internal: &elastic - host: + internal: &elastic # DONNOT CHAGE THIS LINE, 不要修改此行 + host: - http://elasticsearch-master:9200 log: true @@ -55,7 +76,7 @@ kafka: fullnameOverride: kafka zookeeper: fullnameOverride: zookeeper - internal: &kafka + internal: &kafka # DONNOT CHAGE THIS LINE, 不要修改此行 broker: - kafka-headless:9092 @@ -67,7 +88,7 @@ mongodb: usernames: ["root"] passwords: ["qxp1234"] databases: ["form"] - internal: &mongodb + internal: &mongodb # DONNOT CHAGE THIS LINE, 不要修改此行 hosts: - mongodb:27017 direct: false @@ -89,23 +110,32 @@ minio: resources: requests: memory: 10Mi - - storage: + + # 存储的配置,目前支持S3协议的存储,默认使用的Minio。 + storage: &storage type: minio protocol: http - endpendpoint: http://minio:9000 + endpoint: http://fs.lijy.me accessKey: Minio secretKey: Minio123456 location: us-east-1 bucketName: default - - ############## ### quanxiang configurations ############## +fluent-bit: + enabled: true + namespace: builder + image: + repository: fluent/fluent-bit + tag: 1.3.7 + elastic: + <<: *elastic # DONNOT CHAGE THIS LINE, 不要修改此行 + polygate: jwtKey: "1232234yqwufdyuiasdfsdf" + <<: *ingressClass service: type: ClusterIP port: 80 @@ -129,12 +159,18 @@ polygate: svcPort: 80 appcenter: - image: - repository: quanxiang/appcenter - tag: v2.0.0 + images: + chaos: + repository: quanxiang/chaos + tag: v2.0.0 + appcenter: + repository: quanxiang/appcenter + tag: v2.0.0 mysql: - <<: *mysql + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 db: app_center + redis: + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 audit: image: @@ -147,7 +183,7 @@ builder: swageImage: docker.io/quanxiang/swag:v1.1.2 docker: name: faas-docker # 不要修改此项 DO NOT CHANGE THIS VALUE. - git: + git: &gitlab name: rsa # git ssh 的secret的名字, 不要修改。 host: "http://192.168.208.51:8080" # git server的访问地址,例如:http://git.quanxiang.dev 或者 http://192.168.0.3 known_hosts_scan: "WzE5Mi4xNjguMjA4LjUxXToxMDIyIHNzaC1lZDI1NTE5IEFBQUFDM056YUMxbFpESTFOVEU1QUFBQUlOaFNQQlFXYUZLaWYzVUp4aWNCdzRFRjhMS0VreE5jVWorU2RzN3VjZGlFClsxOTIuMTY4LjIwOC41MV06MTAyMiBzc2gtcnNhIEFBQUFCM056YUMxeWMyRUFBQUFEQVFBQkFBQUJnUURBakpBdmRMOEtabkxvbFpFcGlUbWV2S2ppZDZtME5VVktyN0lPT0hHc2d2bnBnVUVudXRwV2R2cG80OEY1cTZIN3lIRkVETUpVS0JqeS9jNFBOS1JhdExpL3NmNlF2WURjcm00TDFONEV3NFliamcyN2UvVnByWGp6eHhUeGM0TG1WNVNPTmpnbVdvQmJGc0xFanNFL2RtT1hiclhRWGREai9ndXlQbjE2dXNhazh1cEpGV21ZWllmOGp3MXg2WFFXelVXUUZBTERsNHdyMnB6YkR5RSsyVzlYeUloeU1PV2dDdGMycjZ4ZVVXTENaZXQrblQ4Wk9iRW5DakFZV3l3VnBnRE5aL28vR0FRKzdBelJEUmxLa1M1TU9pYWlMY2V0OWpta0M5THlueVdQV0hLQWVYMk8zaTNYWERoU2czMlRWeVJTa0V1c0oyajhTOGtJVHdTVVdYeDIvaG1DNEdjREVPSnlZamRYOU9oM3IzWStYVHpBQThNVE9CNnhVVWtObUtWenpXVWh6RGtmNDNqaFNOT094dG9rQWw1eEtpbWwwMGplaVdFRmw3RzVFd2xHWmRaWlk2amhIRzBQUGxSeTQyQld5SGlFQWd0N2ZXSU9LUFVHVVM0bU9pMnNnVDlmOE1BOWgxVVVHM0p0cG1nTzhnc2hCZXlhTUkweTN0cz0KWzE5Mi4xNjguMjA4LjUxXToxMDIyIGVjZHNhLXNoYTItbmlzdHAyNTYgQUFBQUUyVmpaSE5oTFhOb1lUSXRibWx6ZEhBeU5UWUFBQUFJYm1semRIQXlOVFlBQUFCQkJQejZiRXRBOUJ1ZElWR29EL2lYLzlOZWhCd1lGV1EvdHpUM1VkWlkyUDRvcDNBdHpkNnFiODl2Nmt0bzVpNC9GRkhob1JtbEgrWFExSktjRjNPRnBMWT0K" @@ -162,7 +198,7 @@ dispatcher: tag: v2.0.0 imagePullSecrets: "" mysql: - <<: *mysql + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 db: dispatcher entrepot: @@ -171,8 +207,10 @@ entrepot: tag: v2.0.0 imagePullSecrets: "" mysql: - <<: *mysql + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 db: entrepot + redis: + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 faas: image: @@ -181,14 +219,14 @@ faas: imagePullSecrets: "" goBuildImage: docker.io/quanxiang/builder-go:v1.16 mysql: - <<: *mysql + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 db: faas redis: - <<: *redis + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 elastic: - <<: *elastic + <<: *elastic # DONNOT CHAGE THIS LINE, 不要修改此行 kafka: - <<: *kafka + <<: *kafka # DONNOT CHAGE THIS LINE, 不要修改此行 docker: name: "faas-harbor" # docker registry的 secret名字。不要修改。 registry: "qxcr.io" #docker registry配置地址 @@ -201,15 +239,18 @@ fileserver: repository: docker.io/quanxiang/fileserver tag: v2.0.0 imagePullSecrets: "" + <<: *ingressClass mysql: - <<: *mysql + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 db: fileserver redis: - <<: *redis + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 s3: buckets: readable: qxp-static private: default + storage: + <<: *storage ingress: enabled: true hosts: @@ -229,9 +270,6 @@ flow: redis: <<: *redis -fluent-bit: - namespace: builder - form: images: premit: @@ -245,11 +283,13 @@ form: tag: v2.0.0 imagePullSecrets: "" mysql: - <<: *mysql + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 db: form redis: - <<: *redis - kafka: *kafka + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 + mongo: + <<: *mongodb # DONNOT CHAGE THIS LINE, 不要修改此行 + kafka: *kafka # DONNOT CHAGE THIS LINE, 不要修改此行 goalie: image: @@ -257,10 +297,10 @@ goalie: tag: v2.0.0 imagePullSecrets: "" mysql: - <<: *mysql + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 db: goalie redis: - <<: *redis + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 implant: image: @@ -276,10 +316,10 @@ kms: imagePullSecrets: "" signKey: replace-this-place # 替换此项的值,尽量复杂。 mysql: - <<: *mysql + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 db: kms redis: - <<: *redis + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 message: images: @@ -293,12 +333,12 @@ message: repository: docker.io/quanxiang/letter tag: v2.0.0 mysql: - <<: *mysql + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 db: message redis: - <<: *redis + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 kafka: - <<: *kafka + <<: *kafka # DONNOT CHAGE THIS LINE, 不要修改此行 email: enabled: true host: smtp.lijy.me @@ -313,30 +353,33 @@ organizations: repository: docker.io/quanxiang/organizations tag: v2.0.0 mysql: - <<: *mysql + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 db: organizations redis: - <<: *redis + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 elastic: - <<: *elastic + <<: *elastic # DONNOT CHAGE THIS LINE, 不要修改此行 persona: image: repository: docker.io/quanxiang/persona tag: v2.0.0 elastic: - <<: *elastic + <<: *elastic # DONNOT CHAGE THIS LINE, 不要修改此行 polyapi: image: repo: docker.io/quanxiang name: polyapi tag: v2.0.0 + <<: *ingressClass mysql: - <<: *mysql + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 db: polyapi redis: - <<: *redis + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 + hostAliases: + <<: *hostAliases # DONNOT CHAGE THIS LINE, 不要修改此行 ingress: enabled: true hosts: @@ -345,16 +388,17 @@ polyapi: - fullName: polyapi path: / svcPort: 80 + process: image: repository: docker.io/quanxiang/process tag: v2.0.0 imagePullSecrets: "" mysql: - <<: *mysql + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 db: process - process: - <<: *redis + redis: + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 search: image: @@ -362,7 +406,7 @@ search: tag: v2.0.0 imagePullSecrets: "" elastic: - <<: *elastic + <<: *elastic # DONNOT CHAGE THIS LINE, 不要修改此行 qxp-web-home: image: @@ -370,7 +414,8 @@ qxp-web-home: tag: v2.0.0 imagePullSecrets: "" redis: - <<: *redis + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 + <<: *ingressClass qxp-web-nginx: image: @@ -383,6 +428,15 @@ qxp-web-portal: repository: docker.io/quanxiang/qxp-web-portal tag: v2.0.0 imagePullSecrets: "" + redis: + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 + <<: *ingressClass + +qxp-web-vendors: + image: + repository: docker.io/quanxiang/qxp-web-vendors + tag: v2.0.0 + <<: *ingressClass warden: image: @@ -390,16 +444,27 @@ warden: tag: v2.0.0 imagePullSecrets: "" redis: - <<: *redis + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 jwtKey: "" # jwt加密密钥,尽量复杂 accessTokenExp: 2 # access token 失效时间 默认2小时。 refreshTokenExp: 24 # refresh token 失效时间 默认24小时。 web-process: image: - repo: docker.io/quanxiang/web-processors + repository: docker.io/quanxiang/web-processors tag: v2.0.0 imagePullSecrets: "" hostAliases: - enabled: true - ip: 192.168.0.10 + <<: *hostAliases + +init-job: + images: + initdb: + repository: qxcr.io/lowcode/initdb + tag: v2.0.0 + mysql: + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 + git: + <<: *gitlab + docker: + <<: *docker \ No newline at end of file From bae6748b3b90a8f5b8f205ffe70507a2809d8d58 Mon Sep 17 00:00:00 2001 From: kevin Date: Mon, 27 Mar 2023 19:03:49 +0800 Subject: [PATCH 3/4] fix: fix issues --- README.md | 50 ++- README_zh.md | 199 ++++++----- deployment/charts/quanxiang/Chart.lock | 10 +- .../charts/audit/templates/configmap.yaml | 2 +- .../charts/builder/templates/_helpers.tpl | 6 +- .../charts/builder/templates/secrets.yaml | 2 +- .../quanxiang/charts/builder/values.yaml | 2 +- .../charts/elasticsearch-17.9.24.tgz | Bin 93748 -> 93750 bytes .../charts/entrepot/templates/deployment.yaml | 13 +- .../fileserver/templates/deployment.yaml | 11 +- .../quanxiang/charts/fluent-bit-2.10.3.tgz | Bin 14323 -> 0 bytes .../charts/init-job/templates/initdb_job.yaml | 34 +- .../charts/quanxiang/charts/kafka-20.0.2.tgz | Bin 115187 -> 115185 bytes .../charts/quanxiang/charts/minio-5.0.33.tgz | Bin 19283 -> 19282 bytes .../quanxiang/charts/mongodb-13.6.2.tgz | Bin 74457 -> 74454 bytes .../charts/quanxiang/charts/mysql-1.6.9.tgz | Bin 11584 -> 11587 bytes .../quanxiang/charts/nginx-ingress-0.16.1.tgz | Bin 40188 -> 40189 bytes .../organizations/templates/configmap.yaml | 2 + .../charts/polyapi/templates/deployment.yaml | 4 +- .../charts/polygate/templates/configmap.yaml | 14 + .../quanxiang/charts/redis-cluster-7.1.0.tgz | Bin 97442 -> 97438 bytes .../charts/serving/templates/_helpers.tpl | 4 +- .../charts/serving/templates/secret.yaml | 2 +- deployment/charts/quanxiang/values.yaml | 330 ++++++++++-------- .../scripts/init-artery-engine-persona.js | 112 ++++++ deployment/scripts/init_nav.js | 78 +++++ 26 files changed, 601 insertions(+), 274 deletions(-) delete mode 100644 deployment/charts/quanxiang/charts/fluent-bit-2.10.3.tgz create mode 100644 deployment/scripts/init-artery-engine-persona.js create mode 100644 deployment/scripts/init_nav.js diff --git a/README.md b/README.md index d081a9d..5591e96 100644 --- a/README.md +++ b/README.md @@ -135,15 +135,15 @@ KubeSphere cluster requirments: | Master | 1 | CPU: 4 core, Memory: 8 GB, Disk: 80 GB | | Worker | 5 | CPU: 4 core, Memory: 8 GB, Disk: 80 GB | -##### OpenFunction - -- Deploy Openfunction manully, refer [office documentation](https://openfunction.dev/docs/getting-started/installation/) - > **Notice** > > Scale nodes' resources to double and use PaaS that privode by cloud vendors, if you want to use QuanXiang as production. +##### OpenFunction + +Deploy Openfunction manully, refer [office documentation](https://openfunction.dev/docs/getting-started/installation/) + - Deploy OpenFunction with helm: ``` @@ -157,6 +157,28 @@ helm install openfunction openfunction/openfunction --version 0.1.0 -n openfunct Persistence IP address is recommended, that is easily to access QuanXiang web site. Before you deploy MetalLB, you should prepare several IP addresses which should be available. Refer [official documentation](https://metallb.universe.tf/installation/) to more information about installation. +- Following step is copied from MetalLB official web site. + +If you’re using kube-proxy in IPVS mode, since Kubernetes v1.14.2 you have to enable strict ARP mode. + +*Note, you don’t need this if you’re using kube-router as service-proxy because it is enabling strict ARP by default.* + +You can achieve this by editing kube-proxy config in current cluster: + +```bash +kubectl edit configmap -n kube-system kube-proxy +``` + +and set: + +```yaml +apiVersion: kubeproxy.config.k8s.io/v1alpha1 +kind: KubeProxyConfiguration +mode: "ipvs" +ipvs: + strictARP: true +``` + - Deploy MetalLB with helm: ``` @@ -190,7 +212,7 @@ spec: kubectl apply -f ip-pool.yaml ``` -#### Step 2. QuanXiang installation +#### Step 3. QuanXiang installation **Helm Charts installation is enabled after v2.0.0.** @@ -206,7 +228,7 @@ You can download the [release version](https://github.com/quanxiang-cloud/quanxi QuanxiangCloud deployment tool support production and demo: -- For production, database, cache, message etc. should be installed, refer [configurations](https://github.com/quanxiang-cloud/quanxiang/blob/master/doc/install.md#Configurations) for more details. +- For production, database, cache, message etc. should be installed before you deploy QuanXiang, refer [configurations](https://github.com/quanxiang-cloud/quanxiang/blob/master/doc/install.md#Configurations) for more details. - For demo, all services will be deployed in Kubernetes. ##### Configurations @@ -246,7 +268,7 @@ hostAliases: &hostAliases ##### Installation -Run `helm install` to install the trial version: +Run `helm install` to install QuanXiang: ```bash cd quanxiang/deployment/charts @@ -259,13 +281,11 @@ helm install lowcode -n lowcode ./quanxiang --create-namespace --timeout 1800s helm uninstall lowcode -n lowcode ``` - - #### How to access ##### Configure gateway -Refer [KubeSphere official documentation](https://kubesphere.io/docs/project-administration/project-gateway/) to configure gateway. LoadBalancer is recommend. +Refer [KubeSphere official documentation](https://kubesphere.io/docs/project-administration/project-gateway/) to configure gateway if you do not use MetalLB or OpenELB. LoadBalancer is recommend. ##### Access QuanXiang @@ -280,6 +300,8 @@ To access QuanxiangCloud console, you should configure your hosts file or add dn ##### initialize web configurations +**Below step is necessary if some menu is lost.** + Portal console does not initialize after installation, follow below steps to initialize: > > 1. Open QuanXiangCloud portal console by browser. @@ -291,15 +313,7 @@ Portal console does not initialize after installation, follow below steps to ini Details please refer to the image: ![snippets](./doc/images/initialize_configuration.png) - - - -

-💸 Installing on a native KuberNetes environment - -Coming soon. -
## Get Started using QuanXiang diff --git a/README_zh.md b/README_zh.md index 705ad66..943e5e1 100644 --- a/README_zh.md +++ b/README_zh.md @@ -113,7 +113,7 @@ QuanXiang 围绕应用设计、开发、部署、运维全生命周期管理, - 已安装好 Kubernetes 环境 (<= v1.21.*)。 - 已安装好 OpenFunction 环境 (v0.5.0 及以上)。 -#### 第 1 步:安装 KubeSphere +#### 第 1 步:安装 KubeSphere和OpenFuction ##### KubeSPhere @@ -129,114 +129,152 @@ KubeSphere 部署环境的要求如下: | master | 1 | CPU:4 核, 内存:8GB, 硬盘:80GB | | worker 节点 | 5 | CPU:4 核, 内存:8GB, 硬盘:80GB | +> **注意** +> +> 如果集群将用于生产或者准生产的话,建议将 worker 节点的内存和硬盘至少提高 1 倍,中间件部分推荐使用云厂商提供的 PaaS 或者服务。 + ##### OpenFunction -- 手动安装OpenFunction,详细步骤请参照[官方文档](https://openfunction.dev/docs/getting-started/installation/) +手动安装OpenFunction,详细步骤请参照[官方文档](https://openfunction.dev/docs/getting-started/installation/) -> **注意** -> -> 如果集群将用于生产或者准生产的话,建议将 worker 节点的内存和硬盘至少提高 1 倍,中间件部分推荐使用云厂商提供的 PaaS 或者服务。 +- 使用helm 安装OpenFunction -#### 第 2 步:安装全象云低代码平台 +``` +kubectl create namespace openfunction +helm repo add openfunction https://openfunction.github.io/charts/ +helm update +helm install openfunction openfunction/openfunction --version 0.1.0 -n openfunction +``` -##### 前提条件 +#### 第 2 步:安装MetalLB (可选) -安装全象云低代码平台前,您首先需要确保满足以下条件,然后再从我们的 release 中可以选择您需要的版本。 +推荐使用固态IP,它可以使您更容易的访问到全象云低代码平台。在使用MetalLB之前,需要准备和您的环境在同一环境下的一些可用的IP地址,并且可以被您访问到。详细信息可以参考 [官方文档](https://metallb.universe.tf/installation/) 。 -- 运行安装程序的系统可以访问 KubeSphere 集群。 -- 已正确安装 kubectl,如果没有请先 [安装 kubectl](https://kubernetes.io/docs/tasks/tools/)。 -- 已正确配置 kubeconfig,若没配置请先完成配置。 - - QKE kubeconfig 可通过 QingCloud 控制台获取; - - KubeSphere kubeconfig 请参见 [官方文档](https://kubesphere.com.cn/docs/) 或者 [求助社区](https://github.com/kubesphere) 完成配置。 -- 已安装 helm3,安装过程请参见 [官方文档](https://helm.sh/docs/intro/install/)。 +- 下面步骤摘录自MetalLB的官方安装文档。 -##### 使用发行版 +如果IPVS运行在kube-proxy模式下,且Kubernetes的版本为v1.14.2,你需要启用 strict ARP模式。如果使用的是kube-router的话,默认ARP为开启状态。 -如果不希望自己编译的话可以直接使用我们发行版,点击 [下载地址](https://github.com/quanxiang-cloud/quanxiang/releases/tag/v1.1.0)。***注意区别不同版本的系统架构***。 +启用IPVS使用操作: -##### 使用源码编译 +``` +kubectl edit configmap -n kube-system kube-proxy +``` -需要先 git clone 项目源代码进行编译。需要注意的是修改指令中的 GOOS 和 GOARCH 以匹配系统架构,以 Linux amd64 为例: +修改一些内容 -```bash - git clone https://github.com/quanxiang-cloud/quanxiang.git - cd quanxiang/deployment - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o installApp main.go +``` +apiVersion: kubeproxy.config.k8s.io/v1alpha1 +kind: KubeProxyConfiguration +mode: "ipvs" +ipvs: + strictARP: true ``` -> **说明** -> -> - GOOS 可用系统:darwin、Linux、windows、freebsd 等; -> - GOARCH 可用架构:amd64、386、arm 等。 +- 使用helm安装MetalLB +``` +helm repo add metallb https://metallb.github.io/metallb +helm repo update +helm install metallb metallb/metallb -n metallb-system --create-namespace +``` +- 为Kubernetes添加IP地址,比如文件名为 ip-pool.yaml -#### 开始安装 +``` +apiVersion: metallb.io/v1beta1 +kind: IPAddressPool +metadata: + name: lowcode + namespace: metallb-system +spec: + addresses: + - 192.168.208.190-192.168.208.195 # replace this to your ips +``` + +> 注意: +> +> 这些IP必须可用,并且能被您访问到。 -全象云低代码平台支持生产部署和试用部署: +- 使用kubectl使IP池生效。 -- 生产环境可以先部署好中间件,具体内容可以参考 [修改配置文件](#修改配置文件)。 -- 试用部署可以选择全部容器部署。 +``` +kubectl apply -f ip-pool.yaml +``` +#### 第 3 步:安装全象云低代码平台 +**V2.0.0(不包含)之后的将使用helm charts安装** -##### 修改配置文件 +- 下载相应安装版本 -如果您已经部署好中间件服务,并打算将其用于全象低代码平台安装,可以在配置文件 `configs/configs.yml` 中将对应的中间件中 `enabled: true` 改为 `false`。**具体配置请参照下文内注释**。 + 您可以从我们的[官方发行版地址下载](https://github.com/quanxiang-cloud/quanxiang/releases/tag/v1.1.0) 也可以直接git clone对应的tag -```bash shell - vim configs/configs.yml - #Middleware Services 中间件服务 - mysql: - enabled: true - rootPassword: qxp1234 #It is required to set the root user password if enabled equal to true 设置root用户密码 enabled为true时必填 - redis: - enabled: true - password: cXhwMTIzNA== #The password here is the base64 code of the password. For example, the base64 code of qxp1234 is cxhwmjm0cg== 这里的password为密码的base64编码,比如qxp1234的base64编码为cXhwMjM0Cg== - kafka: - ..... +``` +git clone https://github.com/quanxiang-cloud/quanxiang.git ``` -##### 安装 +- 安装全象云低代码平台 -通过执行 `installApp` 指令来安装全象云低代码平台,试用版执行如下指令安装: +全象云低代码平台可以支持生产环境和试用环境: -```bash shell -./installApp start -k ~/.kube/config -i -n lowcode -``` +> - 生产环境:我们推荐您在安装全象前安装好数据库,缓存等中间件,参考配置选项内容。 +> - 试用环境:安装工具会安装所有组件。 -参数说明: +##### 配置项简介 -| 参数 | 作用 | 使用说明 | -| -------------------- | ----------------------------- | ------------------------------------------------------- | -| -c/--configfile | 配置文件路径 | 当前项目 configs/configs.yml 的绝对或者相对路径。 | -| -d/--deploymentFile | 部署文件夹的路径 | 当前项目 deployment 文件夹的绝对或相对路径。 | -| -k/--kubeconfig | 访问 k8s 集群的配置文件路径 | 如果该文件在默认位置 ~/.kube/config 可以不指定该参数。 | -| -i/--middlerwareInit | 中间件是否需要初始化 | 如果指定则对中间件进行初始化。 | -| -n/--namespace | 服务部署于 k8s 集群的命名空间 | 如果不指定默认为 default。 | +生产环境,您需要将对应的中间件启用选项禁用,我们的配置文件在`quanxiang/values.yaml`, 下面是配置文件的一部分。 -##### 卸载 +``` +# Default values for quanxiang. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +#replicaCount: 1 + +global: + namespace: "" + domain: example.com # replace value to your domain. 修改成您自己的域名。 + websocket_hostname: ws.example.com # socket server访问地址 + home_hostname: home.example.com # 用户端访问地址 + portal_hostname: portal.example.com # 管理端访问地址 + vendor: + protocol: http # 前端渲染配置访问协议。 + hostname: vendors.example.com # 前端渲染配置访问地址。 + port: 80 # 前端渲染配置端口。 + faas: + enabled: true # 是否安装faas。 + loadBalancer: &lb + loadBalancerIP: '192.168.208.190' # DONNOT CHAGE &lbIP, 不要修改 &lbIP ---此处填写LB的可用地址,如果使用了MetalLB,在定义的IP pool里的可用地址。 + +hostAliases: &hostAliases + enabled: true # 没有可用的DNS服务做解析时,需要将此处设置为true,配置容器内hosts文件。 + <<: *lb # DONNOT CHAGE THIS LINE, 不要修改此行 + hostnames: + - 'qxp-static.fs.example.com' + - 'default.fs.example.com' + ..... +``` -通过执行 `installApp` 指令进行卸载操作: +##### 安装 -```bash shell -./installApp uninstall -n lowcode +使用helm安装全象 + +``` +cd quanxiang/deployment/charts +helm install lowcode -n lowcode ./quanxiang --create-namespace --timeout 1800s ``` -参数的详细解释如下: +##### 卸载 -| 参数 | 作用 | 使用说明 | -| ------------------------- | ----------------------------------- | ------------------------------------------------------------ | -| -d/--deploymentFile | 部署文件夹的路径 | 当前项目 deployment 文件夹的绝对或相对路径。 | -| -k/--kubeconfig | 访问 k8s 集群的配置文件路径 | 如果该文件在默认位置 ~/.kube/config 可以不指定该参数。 | -| -n/--namespace | 卸载的服务部署于 k8s 集群的命名空间 | 如果不指定默认为 default。 | -| -u/--uninstallMiddlerware | 是否需要卸载工具部署的中间件 | 若没有使用工具部署的中间件可以不引用此参数。若使用,卸载时报错没有此资源,忽略即可。 | +``` +helm uninstall lowcode -n lowcode +``` #### 访问环境 ##### 配置网关 -参考 KubeSphere 的[官方文档](https://kubesphere.io/zh/docs/project-administration/project-gateway/)。我们推荐使用 LoadBalancer 方式配置网关。 +如果未使用MetalLB或者OpenELB的话,可以参考 KubeSphere 的[官方文档](https://kubesphere.io/zh/docs/project-administration/project-gateway/)配置网关。我们推荐使用 LoadBalancer 方式配置网关。 ##### 配置访问 @@ -251,7 +289,10 @@ KubeSphere 部署环境的要求如下: ##### 初始化Web配置 +**如果出现部分菜单栏没有出现的情况,请使用此节内容进行初始化前端界面** + Portal 控制台需要在安装完成后进行初始化,参照以下步骤进行初始化: + > > 1. 在浏览器中打开全象云的管理端控制台 > 2. 在浏览器中打开开发者工具. MacOS快捷键 "Option + command + I", Windows/Linux快捷键"F12" 或者 "Control + Alt + I" @@ -262,13 +303,8 @@ Portal 控制台需要在安装完成后进行初始化,参照以下步骤进 下图是执行脚本的位置: ![snippets](./doc/images/initialize_configuration.png) - -
-💸在原生 KuberNetes 环境上安装 -敬请期待。 -
## 快速开始 @@ -280,27 +316,26 @@ Portal 控制台需要在安装完成后进行初始化,参照以下步骤进 | 组件名称 | 组件功能 | 组件链接 | | --- | --- | --- | | app-center | 应用管理中心:应用基本信息及应用权限管理 | https://github.com/quanxiang-cloud/appcenter | -| audit | 无 | -| dispatcher | 时间调度服务: 定时回掉指定任务接口 | +| audit | 审计服务。 || +| dispatcher | 时间调度服务: 定时回掉指定任务接口 || | entrepot | 任务管理中心:异步任务管理中心 | https://github.com/quanxiang-cloud/entrepot | | fileserver | 文件服务:支持 aws s3 协议的对象存储上传与下载 | https://github.com/quanxiang-cloud/fileserver | -| flow | 低代码流程引擎:低代码流程定义、低代码业务节点扩展和低代码其它业务整合 | https://github.com/quanxiang-cloud/flow | +| flow | 低代码流程引擎:低代码流程定义、低代码业务节点扩展和低代码其它业务整合 | https://github.com/quanxiang-cloud/flow | | form | 表单引擎:表单高级组件、以及 schema 的处理,与 structor 配合使用 | https://github.com/quanxiang-cloud/form | -| goalie | 权限管理:角色权限管理,RBAC 权限模型 | +| goalie | 权限管理:角色权限管理,RBAC 权限模型 || | kms| 密钥管理:平台密钥管理及签名验证,外部密钥代理及鉴权 | https://github.com/quanxiang-cloud/kms | | message | 消息服务:消息内容管理,邮件、站内信分发 | https://github.com/quanxiang-cloud/message | -| nurturing | 已废弃 | | organizations | 组织服务:人员部门等信息管理,内置人员扩展字段服务功能 | https://github.com/quanxiang-cloud/organizations | | persona | 应用配置中心:应用个性化配置数据存储 | https://github.com/quanxiang-cloud/persona | |polyapi | API 管理:API 注册,API 文档管理,第三方 API 代理,API 编排,API 统一调用 | https://github.com/quanxiang-cloud/polyapi | | polygate | API 网关:token/signature 认证,透明代理 | https://github.com/quanxiang-cloud/polygate | | process | 流程引擎内核:流程模型定义、流程调度和实例数据记录 | https://github.com/quanxiang-cloud/process | | qxp-web-home | web 用户端服务 | https://github.com/quanxiang-cloud/qxp-web | -| qxp-web-nginx | web 静态文件,后面要废弃 | -| qxp-web-portal | web 管理端服务 | +| qxp-web-nginx | web 静态文件,后面要废弃 || +| qxp-web-portal | web 管理端服务 || | structor | 元数据管理:CURD 数据抽象,对接数据库管理 | https://github.com/quanxiang-cloud/structor | -| transaction | 已废弃 | -| warden | 认证服务:jwt 协议认证,生产管理 accesstoken,refreshtoken,支持第三方 jwt 协议 sso;| +| transaction | 已废弃 || +| warden | 认证服务:jwt 协议认证,生产管理 accesstoken,refreshtoken,支持第三方 jwt 协议 sso;|| 除此之外,还有我们的博客版块,该部分内容全部是全象开发团队写作分享的一些技术干货,原计划在官网下一版本更新中增加,大家有兴趣可以点击 [Blog](https://github.com/quanxiang-cloud/website/tree/main/content/zh/blogs) 进行查看,也可以访问我们的公众号/[知乎号](https://www.zhihu.com/people/quan-xiang-yun-di-dai-ma/posts)(全象云低代码)查看历史内容。 diff --git a/deployment/charts/quanxiang/Chart.lock b/deployment/charts/quanxiang/Chart.lock index d671292..e0e4172 100644 --- a/deployment/charts/quanxiang/Chart.lock +++ b/deployment/charts/quanxiang/Chart.lock @@ -14,9 +14,6 @@ dependencies: - name: minio repository: file://../minio version: 5.0.33 -- name: fluent-bit - repository: file://../fluent-bit - version: 2.10.3 - name: kafka repository: file://../kafka version: 20.0.2 @@ -101,5 +98,8 @@ dependencies: - name: init-job repository: "" version: 0.1.0 -digest: sha256:ee4aa501e1a96c6355c3a9090506e1b19fd4bc9e459c9e259b7c8a8b4afc3e0f -generated: "2023-02-01T16:26:34.004025+08:00" +- name: fluent-bit + repository: "" + version: 2.10.3 +digest: sha256:9e53a0ca330cd2be8d24f116afb8751e21a656c0ca92838553fa76d0f752d468 +generated: "2023-03-27T13:59:34.070257+08:00" diff --git a/deployment/charts/quanxiang/charts/audit/templates/configmap.yaml b/deployment/charts/quanxiang/charts/audit/templates/configmap.yaml index e303958..c67db2f 100644 --- a/deployment/charts/quanxiang/charts/audit/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/audit/templates/configmap.yaml @@ -44,7 +44,7 @@ data: # -------------------- elastic -------------------- elastic: - {{- with.Values.elastic.host }} + {{- with .Values.elastic.host }} host: {{- toYaml . | nindent 8 }} {{- end }} diff --git a/deployment/charts/quanxiang/charts/builder/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/builder/templates/_helpers.tpl index f049896..10ec9b5 100644 --- a/deployment/charts/quanxiang/charts/builder/templates/_helpers.tpl +++ b/deployment/charts/quanxiang/charts/builder/templates/_helpers.tpl @@ -62,5 +62,7 @@ Create the name of the service account to use {{- end }} {{- define "imagePullSecret" }} -{{- printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}}}" .Values.docker.registry (printf "%s:%s" .Values.docker.username .Values.docker.password | b64enc) | b64enc }} -{{- end }} \ No newline at end of file +{{- with .Values.docker }} +{{- printf "{\"auths\":{\"%s\":{\"username\":\"%s\",\"password\":\"%s\",\"auth\":\"%s\"}}}" .registry .username .password (printf "%s:%s" .username .password | b64enc) | b64enc }} +{{- end }} +{{- end }} diff --git a/deployment/charts/quanxiang/charts/builder/templates/secrets.yaml b/deployment/charts/quanxiang/charts/builder/templates/secrets.yaml index a27f078..583932e 100644 --- a/deployment/charts/quanxiang/charts/builder/templates/secrets.yaml +++ b/deployment/charts/quanxiang/charts/builder/templates/secrets.yaml @@ -14,9 +14,9 @@ data: --- apiVersion: v1 kind: Secret -type: kubernetes.io/dockerconfigjson metadata: name: {{ .Values.docker.name }} namespace: {{ .Values.namespace }} +type: kubernetes.io/dockerconfigjson data: .dockerconfigjson: {{ template "imagePullSecret" . }} \ No newline at end of file diff --git a/deployment/charts/quanxiang/charts/builder/values.yaml b/deployment/charts/quanxiang/charts/builder/values.yaml index 49c6640..2074609 100644 --- a/deployment/charts/quanxiang/charts/builder/values.yaml +++ b/deployment/charts/quanxiang/charts/builder/values.yaml @@ -6,7 +6,7 @@ namespace: "" gitInitImage: docker.io/quanxiang/grc.io.git-init:v0.29.0 swageImage: docker.io/quanxiang/swag:v1.1.2 docker: - name: faas-docker + name: faas-harbor git: name: rsa diff --git a/deployment/charts/quanxiang/charts/elasticsearch-17.9.24.tgz b/deployment/charts/quanxiang/charts/elasticsearch-17.9.24.tgz index 8f85697725affc75bea12a49e46cb8413b2bf666..80f85f84e6e592a8233b1251632fe16548464148 100644 GIT binary patch delta 90429 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 delta 90458 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 diff --git a/deployment/charts/quanxiang/charts/init-job/templates/initdb_job.yaml b/deployment/charts/quanxiang/charts/init-job/templates/initdb_job.yaml index 3c0c362..6356da1 100644 --- a/deployment/charts/quanxiang/charts/init-job/templates/initdb_job.yaml +++ b/deployment/charts/quanxiang/charts/init-job/templates/initdb_job.yaml @@ -25,8 +25,36 @@ spec: - name: DBTYPE value: mysql - name: DBHOST - value: {{ .Values.mysql.host }} + value: {{ quote .Values.mysql.host }} - name: DBUSER - value: {{ .Values.mysql.user }} + value: {{quote .Values.mysql.user }} - name: DBPASSWORD - value: {{ .Values.mysql.password }} \ No newline at end of file + value: {{quote .Values.mysql.password }} + - name: DOCKERNAME + value: {{ quote .Values.docker.name }} + - name: DOCKERREGISTRY + value: {{ quote .Values.docker.registry }} + - name: DOCKERNAMESPACE + value: {{ quote .Values.docker.nameSpace }} + - name: DOCKERUSER + value: {{ quote .Values.docker.username }} + - name: DOCKERPWD + value: {{ quote .Values.docker.password }} + - name: GITNAME + value: {{ quote .Values.git.name }} + - name: GITHOST + value: {{ quote .Values.git.host }} + - name: KNOWNHOSTSSCAN + value: >- + {{ quote .Values.git.known_hosts_scan }} + - name: GITSSHHOST + value: {{ quote .Values.git.gitSSHAddress }} + - name: GITSSHPORT + value: {{ quote .Values.git.gitSSHPort }} + - name: GITTOKEN + value: {{ quote .Values.git.token }} + - name: GITSSHPRIVATEKEY + value: >- + {{ quote .Values.git.sshPrivatekey }} + - name: ESHOST + value: {{ quote (first .Values.elastic.host) }} diff --git a/deployment/charts/quanxiang/charts/kafka-20.0.2.tgz b/deployment/charts/quanxiang/charts/kafka-20.0.2.tgz index 47b470ec00577693186bacbd0a1216c6771cb5c3..cb9e61988b93e228f5725ddb38d3b811f91f0172 100644 GIT binary patch delta 114853 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 z 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%0A@Y`?J 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�O}i&4{;)JrwIzCV3zcMJNhs~cb?VM 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≷%e}6EjgTPu4FPX%8W&H|t=^R-@6}c}3 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 ad3+w9$LFhj{{H{~0RR7(nPN`>z6Ss>&qx>m diff --git a/deployment/charts/quanxiang/charts/mysql-1.6.9.tgz b/deployment/charts/quanxiang/charts/mysql-1.6.9.tgz index 97f088a1d49fc9fb16cf21582446344abff1708b..95c8ae6b621020892319309797c6c1504cf700dd 100644 GIT binary patch delta 10952 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 delta 10949 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

2f~2{$yGZO$_0e#+HF?6 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 nZtyHuA0RuF-#gj)Sg`yHb!?cOkoKExr+(8 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 diff --git a/deployment/charts/quanxiang/charts/organizations/templates/configmap.yaml b/deployment/charts/quanxiang/charts/organizations/templates/configmap.yaml index 229918b..cb5a2ba 100644 --- a/deployment/charts/quanxiang/charts/organizations/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/organizations/templates/configmap.yaml @@ -60,6 +60,8 @@ data: resetCode: org_resetcode forgetCode: org_forgetcode resetPWD: org_resetpwd + registerCode: org_registercode + newPWD: org_new_code # -------------------- internalNet -------------------- internalNet: diff --git a/deployment/charts/quanxiang/charts/polyapi/templates/deployment.yaml b/deployment/charts/quanxiang/charts/polyapi/templates/deployment.yaml index 8176ded..9490b53 100644 --- a/deployment/charts/quanxiang/charts/polyapi/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/polyapi/templates/deployment.yaml @@ -74,14 +74,14 @@ spec: - name: {{ .Values.imagePullSecrets }} affinity: {} schedulerName: default-scheduler - {{ if .Values.hostAliases.enabled }} + {{- if .Values.hostAliases.enabled }} hostAliases: - ip: {{ .Values.hostAliases.loadBalancerIP }} hostnames: {{- range .Values.hostAliases.hostnames }} - {{ . | quote }} {{- end }} - {{ end }} + {{- end }} strategy: type: RollingUpdate rollingUpdate: diff --git a/deployment/charts/quanxiang/charts/polygate/templates/configmap.yaml b/deployment/charts/quanxiang/charts/polygate/templates/configmap.yaml index 3ca59cf..feed18c 100644 --- a/deployment/charts/quanxiang/charts/polygate/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/polygate/templates/configmap.yaml @@ -101,3 +101,17 @@ data: {{- end }} username: {{ .Values.redis.username }} password: {{ .Values.redis.password }} + # -------------------- handler -------------------- + handler: + # topic kafka topic + topic: audit-log + # group kafka group + group: audit + numOfProcessor: 3 + buffer: 100 + # -------------------- kafka -------------------- + kafka: + {{- with .Values.kafka.broker }} + broker: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/deployment/charts/quanxiang/charts/redis-cluster-7.1.0.tgz b/deployment/charts/quanxiang/charts/redis-cluster-7.1.0.tgz index ecf18543ddad4a164c5ba7388577917b703c01a9..6979074e2af7de77693fffcf8cfaae8ccedf1c16 100644 GIT binary patch delta 61386 zcmV({K+?aW`30W&1(39VbUfO7GI}z4@w?IZ$&05ie#b^%auDl&Ds6cAyU}O&)tubF z$PdqRWw?6T@#L}4_PNm6z`BDxOwcMrOw-_^g z4r3WGdN%N|Zd}jf;fLXetyJiwl!bvuXNAa_R#lmZKI7>P&l8cdYq1*K@T?L{8&!%S zJ2p&ere;RutQ0d*mLg?FF|HYBDL0&HQ&x$oO2M=!Z$!zo%oAZDX_oMuB`P;u=Jq?8 z&vl{`MKuj4PB_^$r4YMI4%^Ya ziZ{ik3MTZ{(w67>%FHhxOg!V{P`2UH=FLwQt|Z3-sstQ zJe%!(oxGTTK1*Kk7f-(a`uX_j-iz6I^pwANG5&g*&Yo_~MJ`HiM7qyE7ty z`~NrjdGv_=NsGjaQ0!HvraWT>FZog!QR=NnkKDt5LpXz(T=KbSd~u!$u0@~a$_Qo_ z+%U6{n%&AQW9mkfrA+N}(Q4dhGEcH9mHC{7e5h|li&r}@Yzh2?A-EXZ7iyOR9UqY+j^%B z3gxMSYi(shc47bgpQhxg_+QLF-F6GA*?af!y#=;~P^{b@VQ8QAdRvS=dc=-~^CAA$ zM8iHlwi5qxgAISVf);wAGyVb=~RLQc;@`X&TM9S3kFCsA-x@orGXTN-G!9U?sk!eQ%Yzh@W zZvYe@Ovw+S4V&1F$kYrUIsg_h0%f<-ETZ+?7M5dKnFW6jG4mCU}I96m7pM#jF;+t%i)+Fo@j^3&E~`;d8wk z&@BKP`eP;Ph&Jc?Gs`u03c%gX-B&FDhR^S6XBmZEP2eL9nw7-TZP z)^0BtJ|_#{AQe-|^TBvDC||t5fjFe{`pm`^!`Fvm#;XkZ=Hp3r%UAj_le2&*q-KvT zm(=EQpNUKhriFpek7uXKoR>n2+&u1>_O(BvhEnaOD$%=@7Uf`G$yDrrLJxZPQBjJ4 zr2?7H2l&iQtfsDg7WRc*oq@R#&U)?UNQ7Zeg{Fi;B9EiBWu=Yfn@gTo03#^{oD9Tr zfY=J2h~Z`vGhAQmT`w*V3Y88#Bipqz!O0DZQr>VQJaz9Pd@-EUnNfU-JXW+svEcZs zw*Y+&Pu#ii=n*>==2n$|*X+ExM{|6E&ztAgY4~z&Bc5gI_UMBVWzI8pwGh+`3@8IR zpeVA{kR7W0v0;S^% zY*wlzQ)VH`dYQEzvj4C&VTrr$)xSrLBzjk#Dh)^Wy((M7U`zV} zo31Q)>lDiXd`nF zKVc|4LoXwQl(!FmU0cnigGNBg3|__S1aG&rC~ssUCP|{I+{E%-{BDS>ggCFXQrtqo zGIMqreaZAfRat8J5V0RGO~IdCqFbXcP$I5~VOhRsantCWnxH?qFGx1Yo}ZJAk@{+A60!iD|<=Sx*rcFDD1A z6y%24oE}P*36y^uJ=qt-vdV;J7w})d_~3DyDZ42&szoXjbacuD5bFR!dk>xs7%$|j zQdLFp&^{J_AB@N~u;lu&pH29!{n|1dkyNELD-Z^y2%FuAa@uNA!DO3|?ZMajbe@P| zmD|%*W?~MQBiu2Xk3AP3J!;rfRBA;67!*5Dxe*^sz{d-fy0`SQc?fcy2p?s`7igir~4<4r-&q9Xr%Z?Dy>Y8rtJe z0=Ite*2a(F#(+*$exa0M7gb(=X%*#M<*Zc7pjE9KMAuGk@7%B-`m7#ZrNz0kOTX2k zHd6D-EbQS*r^};9TfwI-F!x!!e-lIN*fvhiqt zkSut~6H6>SD;7MjmZFpi#f?~ap*$4MhJ>Ql?%PGGsnpC~jQlj$ZOunoy*13TC;ec<#ZpUq^lfi>0wwo7#Y zYL{jgkq(U1T(6{HRxed1kV{=lzkyq@)hjQ{yWdctCSQJ1{GMub;b5qsesZ z>qBsc!Po2vylahFIxDHe*mkbUC9sjoF0nV#yw@@n2`}HHyj{DdJp9^P*%(4-D>yIJ z4S0w072|0t(c%_b1la9DCJVOYD?EpQfu>};y;?}^@TJ%QruSAbeIL&0y*KSe%PDm<^FAzz(1vku z_^~|H$i#NT)3g*?+wN-IPFJXxWU5Ln`?VXf?4#ZKR%*dA!EXecW<0;PL>5hDqZwa< zQRjl^bD=$&0SEPe#zc$KLtHUvq#gviw-2tXy)-bZft!_;$HgtrvfW3eu*yMV1_WlN z%0Wn=gJ>tzrigX(3TzYO(GdSX+TDBV_vX5G>)4|pyY>}IndDP(*mG~45bC_I4u7AA zJ}@T^TpuwD1AiV2lGGj)Vh6Z_16c$|KzjmyI|k7gg$tU0N(9-VTVYh}Amehmk&z^D zKzhJta06h#Wxo~l7t0XA3$F)QiITJP9}gh-2tR;u{b5V)Z;9q1yn>qrJGcKailKGd z?m8S7b_}|j!U(LyuB&M(OOZgl0ZHyOn0kP! zZ-+FiGAj;$q~a#jzR+o91+()XfxR!Q%*Z11GJ_XPsM{8+h=vwM(ot9)OW-dxV^f}7 z16}-h;Mrg*W-=FPKMF}Z1@ZEm@X>bx;{;DhZ_w*%)a&(0#-LCf&C->{Y=TTtOI5qO zj%TdOX#{K=BUtD#vO+6%lvi2SXSr&12CSKp9S9facP&p!Flz=QQy8~{}WPlE)7qvy+qa#x!1iEkzCfj5yPW>6OkqY4}9m1 zN<|m=33?vkwTE1{a1lWlf~P-~(ulJ>S-_CIQd2}elb9wqXxVxN8eO0I>l z44k=t?ZIl1!3Ls*+(>4`Rp??(j~qBRyk*OOdB-4+K3KL4t{T>QaNp2fXF(hEiCR+6 zr3oXpf*@b}8b^OF%B6G-4;J=h13Ff>IhuLF*+ATr*bMNPLP_*rUU-Wnc^NFHZUc{y z(0bjp-pFX|WQkay973Zg>ekFhhf-J)*xC|*uF;)WifC(If34YjZ%2I(-0=O3{=n#d zmMSnjTIFDqpuP5d8ewJeTG01{XbN$R*=Epv+}Y;veGu9vJs3XU7_^VCx(8+un6@eC zFiLIHEv_x?Uee^{H`GpB_nn z_3Ot{g#vk3Jkc~ykp?|UV|Dw`$0~Dp{mj2^ z!~@i^XK{$i`dDmjxUouu6@$Y-Y@a9+M6^IAjEhc>porX*D-;jVjW+~3b>F^!r%Y?` zxq-Pvd=N=x(0vFNE2-i1CFQ@i{!<)#Q}M>JxTy6CbsQfkK|p-}a>jBY0k)dOvkb!33uw57^2Q9_!!gTDI+M>C*a zWG!dM!}QzBJ-EWrAd5s>D=9jE7Yc%V-$Hv!M`!t=$b^YlEgIvZPn+RQUC1iK21CgH z0g5~KzhMK9H3#$yVaxZZqj;lmRER0Y{HObDwADcdg-YM>oX>?NEoaXO*8N&YUMiEJO{wyEwhGfR>WoaO z(O`eO5IIW)x5S4|7+UIoE^)+{Z7`~kiQWx##z(v;M4k>*o~;HmnRT(5W^?LkU@D_Z z$+Jgj!q4ZB#sG%90UxxpDJ*AcB59xXRzmkW&jOM)La$dN2Cv~O>ufl!P_CI)+CB&Z zFVz&jOTp2U&lv=Wxmag_Wg86H%azmh_UW5HfNPL_%f{YC2kg~3wV@X}PpkR5fW!g+gi)M?AUfFlDh z9$E~XpOCB-L6%>4{#Mv@&DIG%fyj@z3$zb3J8FrdEg)+;ODb*D@s;OW; zrPJy38NJ5jJiowy?WSw+gp2|CVDc$?7ZsNvw_H&6#jlCSeBe(qc4D20s8gXd7 z2)$P=U~77nximqP9WIt^n1}A8ix|k7#UiJ&>x2G$NH-3`nhpw;p4{bLZ3g{5Pztj+ zzmej0myRDiVJLxh7yH=_&dW7MJ{oH&6@>G7^Kmq~H&DQT2#(9vm%fYUiYcn2(c=b8oJ_=Lmt;0prBp){F+W_ECQGqost2vslo|V@_~)G#G&TUX@JL zS}BIPQ@y04$;HvdyUE+D*UohA!iBvL$FUab|1K6rpB%hl2QZ^Iyuh>hzA-lXIC!%G zA}FGX{`r)DZq`IR`Hd0gZA5F|9hmVeZ;fW|IZ3m@uzpJ;4I=4F7-pJ~{_i%%bQ}T6 zLZnqDO5k|lh0Phyz@==pJ@>i~@fobAjViBu56b1_=~CtrWZHJ%fb(V!d`~r5Mq^vE zk@SL>;=ELeK#q%n87`-9KuB>tk zK?^$&6BuUu6x~y2`kfyiemidUg85;V%61EGH4hJ#Ydq=QkbPx>Qt$%8w*IP?Qwe}| zAK}hw4%`n?&892HN$3EZ4N5__7l<;JDsXdurf_=UG(za#+Do<&kjY# zS40@#36eZxseQ;aJ%!k_2f;2xDZv5??a$$Vug?G%lP|l%KR*NDjLWPl#nqw|dZDtE zeUA^A@lPHO6r%97u7O@wlm>hcP|zkrHfdcHX480Hj1U2z*^9x#qiyIO{1u|WFeAk7xlj}h=-B#g9djW89xNr1|<9t za2t~ELqKjwx-F0pTNW6PVzPA-jE`4bPs2|}qb@2QkM1}P+T{BD4)X5Oc4t^y3SuTq zJKLMndj?UjX2_1~B*pjSGNezy3klzUKt&RfQW(%ad#}~Zytk6*`vou4_Yc&WN#C&A zvde?r&ICMAUu;<$eqkWLjRt!yRvlx-N;dX?ol#U_ zXM=%yvj!H-gx{|rO*LL4u_p%nub{T|!m(eA)kB6(QGx45Pp{nsHbQmR3<&FCC=^a$ z+%BdnP>91)sq1WjoehG{$d-Jy5V+MKYUyq_?b?a?5~e-|%jK! zE_8=cYm=P^wT?B;|y(d`YVLMboTIThQZVw{uXf@@y?9} zskgxab)SYEu#$gCgc*t*AB4pPp)Zy*UPX@+rDQm9lG{s zF718#_MJnvdUbQe_h{UA4ENX3y6>C-sn*?dxKri>YIu zsCD1L_51fRJJi1KTE)-Qz+=#BweZiy=x6HS^(gPs!+)h^|70yZSld>#;yFE`bpCv^ zxWwN$3GXMtDvjBHjXnS$)HS1g(qtXK>teF#Dh(`<0)Z%?#9Ng=k*cEMB?~1J;q_cQ znjw}f;+d{1qH0J@PVnE-Xo$N}d0cY=0{${-OdYaMgXuF}B?~)%H!_zN3qy81V=Gm$ zRIyv0M{^09RZ+oKtRL(P9ax21_Zd(BQfc^L31ufmBDCgz<;t1Nmgx)(Lv=+4HWLx=!Ozm|qkdhdQrQ z3C%-fzln`Q?&2X(AACfXa1K8CR}2)U3IJVwgbGDiL!~w=we022O62YqavyP_1z_O1Zo4 zywCX{3Yxc?wR5a@Zwb1;qB7du=NIJiHd3oxl_e~k(o{qon&YpU5gYM!53Z=77fm~S z`9TSP#*I3RYL;EO(sMz9LGA1IQT;(g@VQFsE+%x{;Zgzrf|$>!B%R%HuB@4FM!%ri z)2I^nps_>M#dBAB@nK_k8KSB*K~~rUI&Tz^^H-x~jY@K~Yk0C~v&|tp5&7IKd_f18 zgB8)ZjyXbe+|8PAApJdP{Oc};h|Ns*BJ`ergCrVsr(qcm1$QWNx++0AdAbGKaR3$UtBizQ#d9>gUt;AM}+?>)0f@7B2m)HzBftypv3f3Z^6L8Ju6JO@hUlG_o=)=x` zyWqKSpS6R?g})%iZVrDMBA&ZY;#@qmUslf^Y>ramLg@_#3yKc2} z;O;6p)P&Q0!CeEAR}j0Qv~Ia;G;bDv5QGCHn4wCfgluNf+ckof`(6? z45KPRPko`Af7b~5ay5b)^iV65Zkv08`Yp^Ck-plrD0v?7!IT{C<3x`SZxuP2%AA+0 z|HTTWwX}jESw{cUYApY?-ElX9%H)kGN2BLRknbWM!+ejvI4Xqr4z9&Y@3WL>xO)1!tt8%b$E-zv?r7!9+$3eYR3vCsuW7^*25jBLXj}-=is9Zy~ zU1<^731%E>%s}x|`+Ysa$G+NVI6BwW=7Yl#xKMQWFUp9B6%dMWoKiD?C`!`Fzc(Vd z-D#$#yQnko9;yVm5BVDkIb5cXM4m#$r!Ed24R)W6N0D&Yc)KwMoEIQm{#+ZY>G&F% zbyUcm6L&{5T5oqvDTJG>d)0xIN5QkW`dAkZoY$Z}!s_OhqYmmnBkaW9h7Axytf{eU z8$mK2epGmV1Lz@lZgdfUNA%R1M@yO8pqsy_DR9r$6(#8RQz)7kUe4i)Au5cIHFr3g zXTVhmwks4M-#NbsGF6 zgCTqM|K54x%T;knh21r*z6!wb6VUX^TkU^z{P47m|r9$`|nlN({sGN|a#6kwv6)(WRE zu}z|m`HWkjm=mzsNDR5Bx4QDgS|KXBLQad6Y1JA*aMymKZbXU6=;tBJymu(I+z?6- zqHNFC3;x}Ae%{l658m*3fT*Oa97M|g6Q0+ycr1p3x==sb#aq3bzWq#;M&|Q(0BU!q zPlN`t{B;ZdL>(|d&_3D+4%KZQ zxZK2tqNL=4cUAEVHU75u%P)R2vtFW>OO+#~4Bd6QJvL+?KMrWMdmq`i-?C8vd1g=N zz0kc!hidS|9^^Nogy05ImZ}Wi@umjjn^emsFIW4Gy9At&^UE*Hj{f)l!N-q1_VFX! zUKznjg-%L;Szvv`hryB>z^%ja8}MVkmh(jm)89oyAjG5J^PS!0@1`pw^k=QZS8O~Q z#og@Q(d&|b`20>|_}{TV{xeeo)X4zbvr=qXB@1#qe?jU%`0fKd_weoi0PB;{!TqDy z`#NI!L9CA4U7<~Ca*-C>WUR2?iS*sISm}4*CH|a$HT}QyC-v(AXyC5_@ zL}AmwKXeC#b?%`iq|bE@b$f(1xiDhwbrE+sf{R!Smt{ z$4|J@kfHNhX>+;KbceB>Eu`qZ-_*Xm)b$g#ZDkrM<Xo-{R+&Uv|G@H*&cTWr1cg6JTCj zTC^k!vCqERMb5nY)z*bDRf$0}MX3tWP-=rjd1z#r1ZJJA5rL4Cv=|z^)$Su=U+~w3 zQl>sVu)p3sQ&XPRkMZxwSU+tj!DQVhJn}lZ20GoU8ybLb z987w~v{>GV@<1&MUJBOx?%VP3>0p1J6ngkWH5CM9_(~c# z8V9c^Wo}qcd@v#hlHI)-Ple&*x=U|;55BJp-Vd+81`qR1*rHn_xD!pUN>vq@)CQMT zRi!km^L2(4?Wfv_1&!nC_#%Xby9I5S{2&O?o)HTSn9S5Mvxl zFhHjfp5sD$62&v26LH6+@0o6h@DOnRV25jN>K$J1DZLd@3n*=&!JDqckVln{6t{suywOH!` z^207$xN_mAgK1oOcR^tvV&Rz9`_C39y;>9v;md)M-Bn+@^v@O~{;55hf|27X)g zUyCkocsKfgplN;D68s=mzu77rOdhxaCcpI-Ncbo1fP=|rtiZwKH(P&z!`GN`q&HrI z!`D#0R7Z;t&LCaj2YwFG@qOP+HiEQ%ng_KnHY}du3T5yF<2JBh#=R0hwwhq0_(%&T z9e+lI7tn|=!oA5svIb~QVT2td=)w2sm)=G|)}qkGL-}Yrij}(`TkV5Cz*6IUZxThg z_G>nQsXG(;^!;9#jk8>;Qsf<&0{YLkuK3pP1oupYe^>40a!;TW+&; zhLbxzU1%ivq^7Y!aLu8pmW9j&<5}iYe3{IRf~u?e910X@&F2E|Mo2i7L%)}+HQkI} z;Ujq3s(WA$>U@903#buPKU*iv#r;sBTwg|AM;!i(^k6dmD}!GT^j4aMs!Z^(*T$^< z@GnZ{toP@<7koMhJf;3y*O++*|L6S2$;sQJOZMaB*T=V|rcRZLOVSC)8l3JdY=62l%i_cI>Cm*;^*lb&ZFIZKwvb+rXIFvPec2 z&7EdA))#*-$Ys_fH}m z&V%L=7+f}-#=)d(7WZ3y?w>?3mhL%xIm_#$lLi+Mg8D;A6aQ&ob@ zM|^Hq1GAo>sBr;jW||de=)srm8SMz_UQleOPA?qO^8$uRBG(I&1)2Y>wzUm z79;y|?NYRNckPPCcaP!K=#k|-O0-_mQG)^B5{)aGyCOz5XJ~s_rb{xP!&B0K(Y_9M z9BSCXlJN$kwUVga%JMc>yIh9o=xj}Jk$;<`vt4nbGqol-lj}s6=Sq%l_qcY~t|$xe z5kbuX6x+H)9OW?YdeAm}1W2YK3}KnBGbmet0xhkr5Tz_8syu^N;|3eubO+Vlx*Al= zI-({KbX*q;iFPK-;S`Ccg>L`V2YbcOJpMmZWswX`H!t)|l~Yxj``-df`2X`ywtqi~ z`Tx%Lixd^XJ=j`%nM*2l@ZKeC8ZG_Q%!)`p2{o`5W@lrRUnY zZb+t&##Qepk^aV|{gqi*O@9hrO$Pp#S-+N2Nki;?OhUPXushdcH(&VbLD{!(lAzG5 z9~QsRIo5LYg-m5OR7GcFK9vWL9i5TN8-2HMaBZ(g8`EM-4CQAw@BOvE({C}}P0KP5 zxXB~f?*0e4s^;DQnJRB|ah2;d8Qwln0$67Md(q#i-~TUnwm;ne?|A^ro%;V(c5!anH3K=Ffxm|2~mblC|tW zk~LQBx3D(jLeG5PbYe4I&f%euAa(eT5TRyih~~Cl{}M`|*0sF`2BiY8>VC1W*T_U@qeBXZIY7+kXq&ocLM%Q0dZg9UvuY z+<)6Ln3jdP*IJ$F(cI;_A9>w#q2>?dS6-{-1`HAK6z|R^%Qlu+4z-QB?8T`c!3ci$ zn!-H!Ki8vCVu}h9@&?stqV69Ex-|Z4yC(nd^tZSBALRe{@u?l3T#pXiwtoTJUbg|F zShaQCAE;8YJ%8}5`Q8UH{|_bR|5~0Oc;fIK*Wn7J>z}UF?XLK5J?LW1bSx>Li(PS| z%cE?Ql1+ETcXtqqfX{WSd?ZWtJx{gN-^y9K@DTWs@BAV7K7Z!&e|J$9RjM9l09xk% z=|6ASe?EEn$p`-bK0blDc%BGV|K5|vxh0J`uA(KeUw>y&BM-SN>yLk@u1dO=1=9p3g|70NuVk4O?TJ^Ppr!lHeC`ZC zZOrfwb3gvkKXdPYlRrH1k3P%p|CcXc*6#loFLplYfA8gE59*WL z)a+Un`?K$+Edc@klO3p*fA#$DXWK76-2d<6^B(X2FOZNvhyi~LF+iv4T#Z3Vr;Bq} zAPH3ER2NhNvv>8W=_Ptih(Hj$^S+x3QT8#zHcCO-8vvi8NU>W~^S=aw|`rFSw#Q(pSPmSfo2V~w&P)`Hoe>1p*v#)p-|7S4y z0FR=!=&}WvVuh=qd4DWu_b#b;tqZWA?L`om_qy;NGR}op+$zJPKV(&EfbNb-{!(A5 z*sxe%m<8|s7A~G8{J)f?8ds@#K=kJ_{{Q0H%YIY-fB7N*`@MYV1bXXC%%t%GxF9mP zP-RE-8Zb}G6oZh8f9B{1K@aV>NWFs(>cMYYJ(z>bgXuLGetA(AvQ(2>d^i4Xw=FKS z_2tDJ{MU(EEmWQ+Lun$$&qpTHBM#P~yWr$5L>wY#=6dv6W^w{vFSJs&BrCN%h21kZ z-(`RqcdYE^-bdwAF%PuGji;UkGIulmvvb>z(m(DKuDH^0f0|FPHlPL)nEhZO{A#vk zhDDN>CffYQ=5kK>$tVR$`oi^tCD{H`W345wdxtAu=sDOBaFIT?u z7gQ?<`&fn!Hvd%A&R3CWSmIO~<8!nHBu&?TYP;j+f4{z3|E?y4=iKzoW2~5KeZ}QU zjcOT)dx5 zcEOjAe=+c|kH;FfnaV<)VO^P%ICBITecR71d}~QFD~@G2Rii3ZMa=l3uiN^LUTdUS zueyJ^PW9yWA}^F2?d!~xg-o(C+RZtSJW%~yHh?AB2(5E;zz$J<_g$?F`~ksb(G3p| zw7+KMofef2e(UA#$M)3th9!VzwNxAuD~Uw&f7)9t81;9WgRCh7jggNMImxssli_PU zQtjg%QYowlaf(_;LoQ}H=lW@zioLX33PoW)vt*Q2*~jo*E?{$yPZr&@HLoSh!LJ=uGG2>huK zoo+{T{!iA~*qHln=gCj*kMFwu?|6?@N!?#CgcIZiNzI)=v-yD3@#>wfy z;RV0-znc%&FBQJSvZRbjkZ9(+??lIU-VvXDCOX@l`2^BBq5bp2z01?{&pNltf7Ayw z=auurv*V-vy^GJ_e7xZZ?4O=}dvx-pcy)Aq*vuGnuCnX;xj?axs4Dr2UH`dQ0$?Q@3=_iH-OE$%mYx_c#l}XACz!S@~ zrzhf8mr&e_kBU#r2Cjx;(yE+7U3;;uhxuywLSsrk>T#>90ol;Tuaw zc6NGxx#Ij=;YOD%LC}-sI&b%nj}A{R=Wy)h3n8m=x(~>ocj<@3=nafSJ~2)+JD{LSeJ9&diTvWcRyf3_g~kR^pWVGZJq24@n(H*)1zVBeTuDL z)&OS3f*QK~iO$?Tf1s{g`v?l?-m{+w8C$f6BduaGZl!}XxmKAn=B&_zIqyY}#48H^ zV3{7MRNh{wq0UC8Wj=8qE$`G9F;_(b5hE)#7(HEY>LYQQDND&Z8;MkB6IFb(>1z48r-5QBHIIh*&Vig=?oZo zl1<+7px&l>DAS&qE*tlvbzR_Ls!XY8$6-s0&cI{%oLYLki+5v*3kf?ZlpG~XPIvsw zeU5jnmq$3?f3+5WCkMPX>Ia|jT6>Rh#A_}7M$Wh!)q+EQhqYaH%Fm;w79NI2JLk1N zAN`=4QWj;EFF5Am6Y=Ji!~8-IuT)vz(>yNQe-F+O4eJs3Le$SQKIJU$wlubU zJP$N5f0JEL6=gC`hO$(PXs|f~`(phKMv2@NWl=R9mUptgd=s3UU&|C1_3gFAmGA(Fq1pug5tsU1KU0$KaMrVcdYZtlkRYcU$^ zqx-D$Wc}}=^W>)%$LcSgjkchy)<_JX&9~Tve=2@jTDQv`3VZbSFceaByIhy+mtQ{f z<+y(NWp!a;Zd}F}N0%piuaDjy9DecU%LSee@@GMrI?;g~vW{2}EbDk`Mru$^mK=(W z)f|p{$47gMJZ!5WQO#}r;NX02EAWGe?kV=oIJHBnNlNz8pN3@W(gLLvjR_euU*$4 za8$K!A8S=(>zVt@lB+i2k>UBBH$HCE+?rvT9)V<2?+_O$$&zy4Wvlr<;_n-Ui05_O zq66XLbaVeyt2#6%wXM0dch`&Nw6Rn}^7%|15ax$deUo)IMW=gi{~HEB&)d8Zf3$yh z)v6A)##>A#oiLxOo@f`Hd0&k|Y_DQZs~z^{(k(yss~E(73s$4$?5XYev{1M`D_wl{ zPMSWxatDGYW0UA~T8Frdo>$%Uu+3Grd%>!~c7CNzd2ws*N+VNkU|APjxGj&g-j*#Y z`jUCGSz`XI7aqH?yh`JiZ#|Q%e_odJ81@3tnc6FNxd5XtqLL$Gp?TXyhQ-Trrwr(B zn@yaKfK|tL#r7vJUd&sq1%l^Np_5>XqK>@=xEO0?fu5L@YSt))-gS!O!X_8%jX-jN zRk|^!7V27RFn^Riq}J=Z6e|C1Qc=q|JO0iH)le>LvnzhOFKeI2q!utDf2gNq7ksU` z1zX{x3l@H^XJGD>78%hWTY8R~zMllWs=l?7u66%2S*8?MIpG_}xls}xnJA1Y<)l8h;J!9rlGP@4SMn!M7s=G0bi zm`dYuhl18xmtAxwsUFDG|A>DtJjAhWC>(G=a`S%=s;q}C#~7JQC^PIR+Nuy+bFnlx zueoK`itcJ>XVFyWmz!U8tYO1<9dH}2^iTidLb-7&ZUg`MdiV%ce_)s3|3B})cvi3f z_Hz3}{kQk>Sp@6<8>`gfpf!+Pblp?;m#At@t_;WAZ6D!p2`qZ0(g1BW0Uo}Zb0mr- zh|zOa^S;#pemzL*@-|m(kpBoG7|tX#Me{?%YLCvuy85BLiOxPh(;?%sd#SZw-{jmi z)y0DDjsvWk&c=cVe^2yCo#~?FVKLyrWg*AoWY}Wi<@Z~kj3unLVcP{(-#f|4}No1ug zCaOGZjl9kaUFxAucg5xYS?mpg#aT#y0a>lO*&7(9unrn|f8&je8l)*~1TGr>sdd`5 z_i7e53S?g4)V6h(RcYF8znjCFLC=TL-0><|$eV*!7Z*aQ4bv z+Z8`|VS*q1e;K^$6d-F({c|Ww(HMm>>BY*Jn4)7Lx0~h(@oqrLUgABHe#wx zDgIBr?(;kYeJ-BFP&HwT-7+=N-$PZDD~HHMZ(ga}y9D*cy~ z{7A&@b;nkG19w4u;OZZ^`frr0i+}(3mLHE#_YRIuzJCZ}%{CaR7%j!Sx^k3BdKmAYoAN0TX@wrPfP+V7TV^LXX z`@nC^ee^+Vyr0&H?vB%3{!l5WLdMZ-i-LSyh7xSj;N^3b4MW5KPybUZ@BcPFbNT=E zkiYG+a(~msIGsCR3QPF^vz<@s^`Ccko{Ajvt|6i-xuLLM~D@3OmUWFPZ+x7~jmb*S(t{N3@h*+67+ zeEqF`&5DIjM8`GN37fS;>UO*HuE2+cP((=SU4L^uyz7P7aJ~pEVgTL8a|o_VSno%_ zFXy-V7!eIEtv^o4z>VaE^(KaSM-`g0gi_> zj2z(suJyb04Q7fJ{OyZ?TwC7?es3SxVsO_-aQ+Ge^@1Y*P(-sDs3KFPGQC7^<$Bb0 z+$S++PnN^}hTNk!`!0Op z`}JvA=DS-Ix0C3t4UrfjGa*OUG8?LqRp+}P8Hk}AP8H-D8he&|;;6I_>v5?vQK+#h z3N^BPNE#slms6OssD@=#CwuiTotLFq;4y2i`JrPza5QWOMkfV_xbw=2YH@jO~ zLrW^AM_>1bdd3j$1_RFX*CGP!T;MG>EV?s5EExZj8vZLTf00$XSThsUEa5EEy@MoV610R z8HSJj?kknf{PUDBxxr^g%w#4fs_3n)@&4k10r?J;-F&(Op?{g@wchPFFq;h^i(u52 z4zPcDoWxkzvEbP?BFT8PrYC|moJu1GcJE7NN+ik~U0mT9PQE-k`A>0_O$ueqrm%WO zmu9dj#%ZOpas>UJ6?&%1sj4hZic;scdsvSzzCJsTXOI_q1grt*>m#v0)!NcPNQ2CP z{0yL*R_5fNSzG&7SI7vkO?wDvAmxp2X_|i)->;DO=%253Va5=oi!?py1%d-AyerlF7}f3dC(B~Sk{Ny+9yztnaaY- zjJ>tXsipiR6JsSU`?g$OC^?)G5n8rrCotA&s&A5Pvb(nSbKLSOpP$kD{q=YZe~xMTQs+9= zliTmtli7smvZU{Nc{bS)jaQfo+FpO+k$! zt&2zNS+C#QUh9gpZ$w_`>%=5Fv!V%Zgk`*zw5x2SiWK-ul8p=LL>ao`;7;UQgt*zI zc9*677S9SCE&C^5o&Z$yPk)>KbGLC@-|fn^rCEuprE$XtIA4+D-QU z3Uk2hwWGv$XR?qpW%vL4^^bD*$A&NpZg`Z{pc((GD5tXIJCa*fBQdH9Tv3=GcC)s2 za(a2V%Va)LrH~G$UloNeqQD>9(Nyazd-DzTEKgObM3M~)Sf+3`+{XH|?QOFGlBt*` zlc_4~IopKR)H`XLz%5vd7QcVn z_$PE?7Y(JQH(4@|m@58h>;Gr(O~9h6-p6q&tt89L$}pEJih{zx466$evM9<9iaT>> z=FZH8nR|zO?*O9^Eq=6I&`gtDLQAtf(aOv%S4=Z)g0B2cRP2!v&>DXu+QJevG5Ro_%L~VqF)fHMQ8^0{D3aRf?~07TZ3 zrx=5#OUQ>@GHcAuJNJJ*;J8Y3(Km`g$bfnUV^N~7^9aU4F%@N+@u~-7aSpH2+gph_ zjw?z;S2~Pq9T6F%Av3jkET*)!w;LA`igT3~nR|a)NI5pI0MvcAU5&cF{hDGwon9LC<+6~7MdOG zPvzzW95+xQ3U&Rz-}^V6-ZiP;+k8gS-0_W6J3zZq`s#qo)P?kS~k# zUqOzC$}NV_kr@X;Y!*SVhVV26nlI>QMTw&YW!gcs_azE&gBeOn&ygY%HuMUcCv;7h9;UNIl37f zo54^Rqpg2Ya)3(dRMAz6G30Pv^PIF93^`nf`I1JXnS;!T!*wk0cLAH5pfrT$?(t7M z48vp!Sy+IEP?0zlAP)*)LWU@%YiKJ6^7q#ejDeX@O_6qeiZNxPHihP3NhOMNz7I`e zZPVRYnI=L_YAu-657V3?+CCV%I}b&v0xdc5`SX7etr|)&fCu8g`80DLQUq5>GkJ(a zn>p}p7^aAOwK)pSJgveIHyCJZT?8jRpwW`Y3#^?1il!!$!6L)rXlfvbK`SvsU}^&i zPD5BI6WTr0G({ns=G~TCi!mj~n4Rf;PB0{q`z|Fj*>)#~c;{jrJ;QUH~7g~hoL*k+XaScw8jaN#aIH( zIG}@qkua47fXSCWg*ezS;(u(Lrx^^TRl4}A7hLZ{#7jvaVCxBpDK6YP#Sek8dfIHz zKm$4)Ow&e)iJ)@35A84n)9y|#1^W=%CwPB{t{rw9&7;-ENZCQ<){0?=A?{Y$m+JUn z`^4fbi&GlLx{{cHZ2LW}qf*?=(JVe;p%2~pLi_CeV8#KCf1fA(f+%zWf(HFfsip~1JR7BrWnfrjcnTuhHZZ# zzdi4>p$!BqlZztK+r>2AjMV13Vx!Z2$jdZRw*#%ggfTFogkC#7&7Am7Fx0Xm8QN@e ziXnW1CB|7Dpzx&rcb{TRDGv&gw*o`POvSKcS)f8Xj0JxFk0JOsFk~&PnsaJBEygkh z6$ywc8jNrH?;_m%K8zz-#ta3*5oUjlj^Ny#_(`OZvp?TDV z{z}5w1RRAFY3M=4zC+%7zt&vlvBF7`$%y-+P)_Ls3$HOXSkAEMW_sz|EW<2;S`_p1Fj|y-d?$ z^xQ>>pe!E^Mrtvlh-5jE((!*Ok}ScsjU8AFm0M0D1*lnGn!;iD5S-?T4XgA108^9f-vk zOpmrA1kKwp)eJ@n61WDgFI7M?GzEQY1vo>3^QA3ixn}f3QQ~teY~FuaNtxCVSd_ma z63`f2t0mQKgpO0Fn#B<8msn`QZC(SG7<^I4f^D}E7_6h%&PPWxyp+d~9!XFH0|aLG zo*AJT1`Rqmz{_B;U@T$K2C(p+Ot`+{yz{n1j)$swDs3r0b+jhhGY}-CA{K;HkhVv- z8BXIo)8A#JLR@@WMtpy4OjdlH44(du6J+H%?e??~L%>Mgn}bm-hHWw+6Qx=ez1cQT z3o#r+Sei#tiXk`?{|i{Q5X0D*7OY}178~>5TgDb(sL{h{bhcR>i!sndEX>4>LP5tY z=1Wo-&1itqOIy#%xKWr2X9*3aCQbSlB+0Y|hT>9ge6=%oR4RXpzC;P6f*Bto^zS^y zm@+Ile2A;_P{5F)HAGr-SQcZjhOAYTK}i1FPYc%&#u`Et-R{G97?OxG$2b}zicB<1 z2(ezmdiqi{V}z1`Elm}skg%kNP~(ge)rz}YB-@NNQNYl>Tg^IF8bcSra5l<<;TjEz zoYLYO6|q7+sn&mEM%;q53@GJk+S10+GVdCH_hz&DVT=tc-gAuvZ}FCF@27=f-F!sc>Hb0RDHL z7V=V|rfU|`(47Y=+AtKFTQ&NBBPh`dm9P&T;Dy#iAqh?0To}96UW#LB<6>cA5b6ul zr2jpWceD0V5r!t5(>J3%rQzW8rcr%Dc#Na^cNot3gWt_8!N*L&@I|{6VD#JFo{VBl zX;&W+Ou2v38HTJ`mF5;nq~o(@m4;;C6`Iyk5ImkX+-ZM+t=4P+0*{6$5L@6-Oc+fO zSlT#vY8P$|SP zzR1K7EbDYL7Gw5J{tGBKgCU}{G=edb2xfQZzAaXtA~}&S7}3g^J~uL?TDe9OsHZk zQHmPs9U#G`-IJi2$$N5*p_5Fg)?nCvNl>D^C!z2dtdyyAkD=2{sFq{M;kvd*&4!^o zNSySf2$PFW3s)FA&4g+>hV7XI)lA-#I}CpvGNJyT%zJXg&>GP!Gr%xC$r@%smMCbv zsDWenP{!EhQP98GEx##Mh?kOZ%M@~qW-tTJ5sbei5Rjzc>rj8| zYcYl{&qF7*URVz2fLg~A+&?Px(%zL`980*gx^zo>*KTqA9G_gkU*PO6t6q$_Wc>(= zV=Sof9IEJwN{9)S0?^+RUM7FHTRg;5Q&mnUL+@-qY>K^h7Yb&yyDq z62s`s$W&krz81bGfJ$mHiXa>zX#IcV7G_jqKa*o{j?h_LTh$@VG?q;>d0LpbA>Ju0 z-yK=m@5WP%DKltTkZddjQ0WF{M%+*aOY(qCr-T+O{vR0XV}rB}o?=WHuJ`GDQ=cMoS8`BH6_sBRNPL!ljdGID;DuD9=PSVO`NGHirJ(1nNcZ3bfiDl8I{!#^EhmP>&a z!E7M4gxaDu5Tj^1&#mV-N!${~S`eJr1uUsjiKz%J%@C+UHrQkE;u*6^hQ&Lt#p4LG zoe(C1S$y+}dp{uZ$MZMRh>9Y$N$C~0d(h!-AD4Sj3^OvV+e3aArDA`#FsschM;nvK z0)iq~HjSZGuFgTBgqqbxW8gcXdPV;nPCJ-g(*}Y$gTOVUTcDl5%m|&@0O%ILoQZab z>uJV{u~^tr*i5h~vaQ*wIEpQ0H1$uga0@d@k(@1A#~t55^ei<9w%J~EOV50KO|$Z- z05jjdt-*E+vx(NUsP=!GtGE@1^xM1hxTOsfL((u?$bhqKitD&OyR$nP*0Y8{I*f3a zV77CqNzZOAsWalvGJU0kh~`;ZTu5^M2|5h*&)iRLVHV$9=>8mx5o};Q{i4!&ZImI= z{5fd7QqpbIu5imGijZqlkXt^_?!v{3F+L)^9RO|)W)rPxQB{9TyFKV4r0=dhZuy2A zW2oIA?P?iqA9IuKyKzOxt}!2=09fRhAv5tSn%DGUdP%-w?7&Xg+A ztwfS@OKN3EI^2H^@La)c7XalFW+1hZxFL=(;Fe56O;Z|yype~A#0{7Ryu?`a7E*H? zpizt|LtWaDq%fNZhJ;3R5wyY}Y4BZJ1KWC-`6~^a09}k_@z))+3(&2AS&QzD&C)Xj ztEUYbv2TvQR~F-hmu(4kD_~~LFeu0=%$ew2yTL4X2{V5q(Oz9M4lCb~cDQ>`I>79j zZ`i@?l5x1>8*PAwTiURL*(Kv}$~W3>&RYYsOUB`xZ?qZEt)XX^jKdY*Xd|dwGtVv= zhbz9(b}+l1XR%qRMNwK3J5rlHZe=71%x>bXZIRY$J)zEnbKHjD7h}r6md&$k5y>sD zYXjJeF=c;nP>>6Migcb`ib&3RUE57G40>`Y^NV42Eh4$#b!`T;TfQNI*|mt|lGn8n z)Ww)GtYt8}7Li=?y0(MaHLo+#niwsrWDmp1Txak*SU_>UA7+9bWmuxExQ!6Cz&C;6 z5U>rb?n`L+_|l=6lBKnr5~CSRsmE>Ab(*)yaAbe8a65yU;>dtD0=!uG%^A!Tts$fU zJCBF3gBf(QpJ*5fahHI0JI_vF&U02P#~IA1>~bCfO{J)|aZ3Ph$nXpOP3Ii|L? zzq?*6XE5{kCkxjDqoAlSvBJAu0Db{+If>g)p32Zd262;Prqqu*B8;|U7B~5`IIHBeluCX}hdO$*g(z6|m zZh|h0ZRIMhA&S1}I#HW3U+~3~S{OFoUT?bi;VFbTL|BD;V7<>W;d3+r#LbKe`UiEXLCKmwYLdwyq)RYR~+avSMAW^?xa^RRp8d zm?6%S`X`y2?O@h$$kuFqvSvG2HXOddUzEUKQ4SbobJkF?0~XK%??5D{p}>D(zPggc z;w3C+Yi83fRzm_N<+_rNbdW5`r7=bnpp8PB`Lre6P>5StOhsT(kyx-ls&!RJvNpR6 zG}Qpipn*nsy}_)zN_Dp8r?w?5%fZ1R0TUgoGF+ocamRm}im?$iZ6I(8 zrXTY4KS(WRq0Lw!j;^l+kfWKg-GpQ|=>SwMTXZ*DhzC<`W*CCv5Z6i7I)E%@NPJs^ zh1Y!vjpJ&!e*3%Un>?5lVZD(zG0mwdPIwKe(VBf~y$-~>^44S)qL2sJ&iLShsXC!e zB%dS`97C#EYlhX|7EXWK-QD6G2>U`4wpXnZV%ps^(@G!^nHkaIwcs`rn7Gey7)qrJ zfGf?=MuO85W)|`hrqyS0s~^|ZPNe9#Df(p{Nm^G!fWKYqeYr06W~OvD4n6>w47Iq&}pYiUO-Zm1q!5BdR?x|b4k&$D(r5EO*q1=3nO$A6n|9mmbXu|$>X|Gl^vrl;ut)}T_GO9 zdXGEQ;8Bqj&RB+FCYohQpuON;vubXv?4oPtYQ-FUPBnH+|bRnjNObqHRK-E$+ zxQW2{K`>u4OJFK%5gLC?i^FPDux>VJZ^L__(5Q7WC4Ung1ScO1F8I@g*l?r{qJ@Fl z4MK`!F@m}qCB@nR9Y=RZv4o~5mcuEvt!8lhL{$7;R^a6Rm16rH-j0DG{}df3!9ot` z{2TSv|0aJrxwHx%Lk_+c@%?_tKS?7~Du**VcmXVbn+&QMhNCz==+Xo|NlK*i{f(UK zzqxl90>VmCI??K6pdV4>3^HPvOgxLjjV1%Z3U#X>a{w&uZa*y*LG92%KWB)M5=79J zBSlg=g1x(jl9r-lBY_OF!D(_Dx{4o`o8)K=oZx?=I8SMJB>jjOAuY%YcLALiNd-;5u%S+1 zWT_#w7HkaQECyR9S~ItUh`;G97o->ywXmjvKsPC@qU~aC-QOc8`ld67g!G$sS3Q5Y z@%sV*o?v=#65pz zYF7MEER_N>8_?#|dYs|-TP$Dz1gzCATqz*96<}cxoYJ9C7ofqCYA9k1WQBk!HA83! ziX(9Y>yNQ!wH|B;GfOaNchEN2Sbu&oMiB<149gOa%}PcW56W8zZ8-}5n1+DG;&IA? znQS+83ArM^Y2#Qwq{*o)h?IXIu3!!sA^;79k(@t(&CEJOO=TtxTmVU7xW-6QBrL^G z7J%uX4J<}#G3$LEGEdJKz6>8(Ko~6k7>-SdNlt>7y(869P-f8LiL?%QnSxbh5L8g> z^$LZ065baAsY{??h)U}TGC<3JSZ2YE26uE9g$){%MVbZ;8j4Mz%@BVmVUC29#7Ux| zrud5f;fK1X&>V_X19O*WMrt*~f+1s3+znO$mJJB1wAR+jw;)KS2$9J#9PvMnL?*66 z2Bwbsp{W7=FeTuD=!#4y6ac3kX9$d@3>MfOiXSQq#?Uk;!^WaqOGp(wQegT4ow{R=$Voyx*ef{45k`L#O8EibAcVLZ>ouQB%z8bi42z{HmejzIN9&48Muz1{c^>8D zLf1&d;$>JSLD=SuWLYzTO_C2866DnFmuFSk0);+-un!vu`uL%BLS`r}%^2YhkOA42 z&twxS=faCV5aj3w4Z-20fkk5QB>oBvY+NRmXf&G9gmbt~q`H3tWnIS441~>=j})k< z3j;Vh&`fCvhUIWd6Tn}U5dg*r5ViF4^h|_&iscxZ(itomLjVqmyal|qlazqK*Op{x zjadyr7v;Ihuq-|FHLzxeU@;4A7PA^mLlcN2@|+4cb2OMEHM}UE)Y>8df!sr~eEI-? zeLRk7NUfHD6pw#=@t&R|&;%fhlCV8-7{i4K5{>{JQh+FJDO-T+z-Ij35sbe^oTO~+ z{4ti)Q9xbADeK*SkkhHbE>hzLtiWub2nJV?29g6@i6|mjPKMSI-3)AlT0)@whdn*B ztWvuj>$JiKxi5_E6^(E;)Hd_ag zVHt!L2~?ozB%T@2YA6HPibdOR4c^MmN;o&z8+y7>pgvAd7!d*RmkYztJwSnE0nXV% zlH6dEkk$;y8K#Jd z;s(toC=*&hN~H+2yYzSg0r)eZTMi4B1fQb|j5wOZ4WjUL6qyLf05_=32Dm#6WF8TK zDbcG)&^T3#>WrhZ0D~QW8e|P3SIV$afHC@u4<*(vj2?@`!uUHV?c>(5NRwvdOCCs+ zhJbToW(Uq&8J5VeIB(v(4s40YM7QJD$+6Bam`H0AF?$3kwQjvEjTL8O7Tiy{$&a{?jw! z;}SD-(qb|*vr{wTO8lkVC*0o!xKKW{f9Y%jBE!6sROlvuQDCBCk$|3M&-s9wOj2e* z?Yw!7Az+zQ$V|XF59VHlBsM-|D&I^qW}_g-8)!jS?$^(jsDAQ{q0xliQx0-FfO?EKt<0BmE*lgDAvK#VFbg_jLg$BhQ$gANe-)R%&P^3gamarb0^T8X9`{D59>{e)E8kc`LS4QujU7Y%V=fF zFsMdrUfu)5A1cJ~w8UjVyrxg-gh=bI|sK*OH8>mFVPlO>b{88GJvl#+!_*QMIa)o(+ zV=`NWhjZU05PyuRxuQjmYSx2SlU2%npq-Epc}y4#6KjE1_J#E{j(&cL*Z$W zQlJ9RmptuqE>TZNW{@cmYMzuBT&pG3JfvAknVz0mNtqaHHo+_U`4AL-5NmNJh@8qI zcyO)Tk2A0`rC7#BIyIs-XvN~U39>=kY#*X7qPzsbge#DiiC_#CF|!wgDlHs;g-oje z9w7jAs1S52>LkPB1aG0uerN3{nP%ls6u--F7k)iastBSyv|ZE$!$EI52bf$6ZS_aW zgmFO&u$X`rltZytTL(yn;Ahtz#}F15ee(!Q3;M^#h`YzM_=_vMv!dH{ z?WX_^%1Ws`&#WTUoYkSocZbG*JW?&`9l#k_o}jUS04+ls1HgEZvOv&EW+IHveg-pP z_cIRKTDdIcZw+B`MuJjkMKl!Y4R(>Yrz3SldbWN_ikQ)z$zEj3gDZ_@xS^O_5gdXRGLtlt2AnZiZ1ZHRXKr7sSsc(} zSLxX{c{ZG-ZT=<9U862?mAEN7ZgYRy7ZGz;sodAh5?Zr?C;0*(&}(ciZ5D=|U}`hV z(MB}ODEopHk*mNcl+r@<=rn@zzA(??2I5&p;$QZtn5_75@fmO=LZE~^6#ao_!7gT0 z{B>MZLLNprW!mvur?^9}58P}1&T)uMlN0Va0V0!4?rncDX^DW6i!9c3SB?adzs4@y zNLUV@8b;A9C*)D0&j6ZVI3lbC9-=fBVHSqGpQ0OA`#4vH< zhxJF^D2q6202ZhssX$iG|0_Vv|D`y9XR+uLSU@305u8j-Gla}KFOl+~pr9bWA)(gO z7)2Bi3>Jl1b4LQvk^~x!fui}!0rLf>E071-DYt(D=!&RHE|V(;OMT@gc#WkQX1UT7 zM-*`~1TU-POMM6mFCVnQzeORJwm=dTbYh}4tPG16yQd%rcKiyMJboxKOLm+gF;YeH@V!tqA8mfY0k;Om~9r%A?6385YrP<=z#S`Q&(lhyc zG;n`xQkpHYAKk!VwXaQfJ{uF;$L>$T=G>Y`MRAS4rhP!*gzqngT&-Egc#tu^cf}v}*}UOEYRhJoh=c!H|Re{QTyz4mH#hvIHwZ zSLFv5HL&hwZ@^7d1c%F{lPsOS$mx^4NlM2MEIZkIDEJ3Uqun{#d+3v3@sR;Ylk)K@ z0kxAI@<9S6kdt8Y_W@;-So4l0;i7+};6@_Kd7K8chef%_$L3vp{AJ;Szh=19%@<|k zrCBr=~LrW)k*2pMy9_GC^T7g@2VbP&6m5f5qU1GQ{!CEWxOO z+DmbeM?w1J{~sn(1O^2KWW*=M$7IICU}`_xl7*lpo0LjnDRcn=9rf~He@qdi2=Ye^ zvp`{Wv=yQ}1S2&4q5Ka*xNP10Cr9%h*m*1HWvURT8P1c{fV)HGwF8Npj+%MlgWC19dR$VI3I3n8+| z2PvqWR_+N~@fctv#}WoDpIRkII>MC2rzXifJqHcShHgS0@In~$PjN8)SdTjBGm-N5}uy1 zw8_GdIz5LCP}3&MFd!f)goX6<6l22GdO{e%ALEZLFh`g#XyDDi^7b3% zlf3vg8li!Kg@uJO96~9h8C{?OwPFL45@X|2GUEf24Ea5O$7EuOncmoln9RgXf6wg1 ztWl|Bv#{)#jEtC+tiFp;eJ60!Jha zN+FFC8YG(a{A21J7;~!9X<|9CkRR@q{(e_`}Zu9hs-c z|2_ZtM_M_5g*57_ZGa*j5EK$156+SY`2@#=MEC^91S@1=3dKa!9@h~RKVYaV z$VU<6n~bYTilbS*A8J8xxDGW)2*UAc!J5plkk|?O@#?hDA$j~)`GXHNlPhFHWO6xr z!&yv!1o~M+6p(5H{2CnZ6CBHf?xP4Id0=y5w8l6&Y0>KBp)^h;>gn(tGzf(o`9acf z9T6Z$gM^OLr>KUog>h*?@-$;uArq%B$~6|?j7g)*4o;&9eL6c$KS7rrGLjsfHql2h z!bg#SXW$VOk&$B1sS>8i6SN~Hm?9=7M8v0mCh5nGn;2nGWU3h5*o1K1SRciRq^zQd z@bs}GjJk2td=v@Usp)K9BAFXY>+&W{!?V&Ag%ig6C=y2Kn9zhFA=6?RCM6?Q9Y0PH ztQwJ>njTs-COS|<^^%-MoSTwkUc6fDN)C2$EAg_x|EFZCVlpJ zI%Ps(TCCidNu|ex(m~+~L3t6QO_qX?xJ*l^$}(g$YZ;L^Cc~f)OAZ|qn}>&g;p*Vv z{DkbWqYB1OOIEXKqhm5G=3Iqgh*3XgB0kDsN--1E#G(v~k75L?pefZvGK-oJo6xueV@#^^&v>L!Na`FY`B;o?G7 zSqY)R2{=L@~$B&q`dza=2z7`MLker+qwB#B6 zJ7caaSe*Rl@KtYzE?w%?`Rg_UV3TYfS%pr;^H*j$~t*_d#~?Q z)uC(GuE%Hmhq`qb@BifLwQJQ4^?$xJZ{D8T;~V4!wc|TK734AC)lN-KO~2Pv_WR*8 z8T*4$KH8Q&-(p${qDVc zRSorj?%TKT8IpXrZtduyyPHNm)(||PtkVMxzbwgFuxQZ?uV5|a>-*q}q2?DhZyvUD z=guJgw^;c>?bj=Yb9XJq+<9+>~eCWAlfjf8Z z9P#rnznnSxZf3-^I$woCu})p}$nHIR@Nbq630ijWsSy36BVuC@eJ~;T#;sebeGB@Q z%hmTUT)1$-iWLF3hmH7^4*@}cb^dVTrz1?Jps3rIV>KF0#I@dxfBndXH5GrHEnk-& zAK!7|tFOMlZTRqjn*7|`SQS5u>QEa)3+s*b#l_3z&yF){I#&jA<#XO-vy zCjoz#5CH)mCcpP^Ra~zRCTzHW>$Gb--l25-;b_%b4+b@WlheXH5KYjxuvr30bgr_zt(Q3^OE6T zm&;$8J$qqPY?s*r0ZM<+EnBvvO`R$$nf+k>z&VYT(TN`&t~gUQV~^_j&6|f^{p+ta zsrh7g+2rSzEn9Y=(G@Yr7A;=9D)H3;hjkGh8;%$BsUNv;?vE9CRooxn zeR!p+PwA+Nn9!HG0|6UJj0ykG-F*zJ24$VO`CP#&-dn{pucgN|U6~>E0T%M0QxW;NjwulEsZX zVrx@NYUlTV_s1Nc*tsu1f8PUV4+L&s6!oHE!NP?vtXzqm5AHFe@!k22uk>Hs@c!!C z+B3R;vF_D6uhRFg?paOtDC-kF_1gDK zWK*V{nDbTcr`|HzM;9*5D=SMNNx$corbhad zBz#zZ)2HFp-Ay$WCw+$v=>6;se0fCv2!zYrGrMM;`*7pQooDyVxyR$lIUSptn#OO? zCLfz~{*RBh&wQJVFrD^TzkdC-e)tdBw28*T9m^Z%kB`)~3>ndUfmFyZ658>LpRYP#$^>Ff$%g3^FR&CjT z((||KimKxqbocyt`^crkhYx#rXg7Fm&>np6*7b|WH#`s(73J&iKV$p$?HTm%o4E6j z4UddmQ~k~p{LymcX`(7lsa#pt$-F-QTtbJA9anw+`BPC*Q8%uApHrznb z%a)#1WxaMyqPPC<pP4r>-qeW zCEXd8y~iWx*_%FJnE#kLd-m*q_xfB_e>$-;_t>BtH*TEX`M-yJ0|NH^e(0^Pk3T+R z;ljs$nVK}{c6h94TXY(G^57QpAK$&#{m7?z-vc`HpYp}y9;UOqI~7?hXZ9~1T(i0G zk}>Cv>5bREUq$wK_V$&LbDs{s_*vkoKaX#C;L8sS`Kwbir=_3y>1#24rKhKlF0L?_Jl?(gxx;J5teg0u$8&k#e>AqS^ybZ* z5rr3f`agNVcqi$Xjj3brG-Tblsxub+`NRLddUfEKiuA$th20un-O)s;N^h;IEiVtJ zPZ}?s^f_15@aM)W7dKyj8V#E0CIdeAZBFu{UfrhG*T$UMRr++f-aSpD7J4=wi#smA z$K%YIGhjDP-r_qxkG^A3l@Irn>h_s9Kn&-2`KpXYP$_v`g~uZrNs0KmZZ!M{c#Eyp>& z=EkgoeD5_5)0aIfKrmVSZRpW1ly13~PU?!vwHJ4rApJ~BWd>@rNpKwnR?duzcJdp>gYm-AAYqqjPI6Q=}vKe22nZf zOlv@MOxy|FF=#zBHX1Juw_^JUh!XaGx}0HbfO}T-jI8Y!bAkK>1!D=xdWmLzqd9V^ zKP%!!ykb_M?-Q>%(Bf%gInz_W@Be`VRN&5$#Rs^%3Vir_$xbIYxb^fX=9H`d5kNY4uV1cLvT{UZ`z3&&*@iBjwW>=}Sw6s#_gtVKEPHy|U%*GZ{OR_}{um_VG zj<#eZWkvHr50+WcOgJ5Qeni!wSNl3F)>JrtLQLG>v&R}*EnQB0`X zI`|Zh5o5TdwSJmxf3gQ^d};e&m}ekF6NZaqR9S2yu6e*)FPd$76NY7w%Qh+pc>O(y8$Eur&BW#)-wo&SlJ_usgr%N!5^cS*nLki$I47b?DS5>?VYTP%`6nW zArUm3DDS@Yk0&^lG%h|mf|y71sl_vw@nm@kA95%~i<9!X&#Q~s#w8QN5s@@vK^Fjp zikUW!wB)N7tAk)}?v%qZQ<}~m29teN@Y+gQfp2ec)zMauW-VC#%N_cBVjGjI*7|VLk zRu?5u`n33x#?C{CFG3KH4^!sABN@I&MP(`)S6DADfun)q0@T8gcV( zwKudaI{`%2@Glpz$X2nLc<%ln?1@uXWktx@K*RZw5YqcaQBefT)!l_A{HQwTQBQBL zK$>z0$lM6`ESYIPd%4J_e7JQ<=Q0;%%J404W6=z@sGRmRaB5#u&TfL+J0AX7)KPCs zgxiU^BT!J6AET1sr`g|9IjaWl%g&5^zO5mI+(=q!xDA$RR-1Qxg8f5@{5Ql7TqO#t+doka5ppa9Y!X9t}9S#8C1TvlX)%j zt)fZRR8H=@+#9tD=pxq$!q=ue4vLASAU?a_D+)fI)DIjNe#OIs9{oZ;{e1F$qgr=A zWr+R~_p2{EzINP7V{i7RjoZZGudNEs4w|4Jt@WBg8rSoy+B#BMQunO${drXkix_GK zR`lQuKbVf@qHQfy**E(=^3nXgYziOE#<}6QZV>j{$)%_=T;ddGmkK%@YO-#RQ@%L) zlE|dy4^BW3WADzsF{*M_Cw*rFl@o{-0C&kQD0cL#LB0;8dh ztCHvao>z>I&r^sDmmYFx<;7F_q@V7MOLm9IRzaS18iZsaMon^F31?3^_M|9*u?Zl@ z=C;*7t>nccZs@Oq6}@z7br^Xxu|g?mK-Zc%+4TE+nhJtN9@G!oh%F6e>H|d$*u^~C zc)Kb%I*r_$P8|;kc~35MnWhXOcn+P97bTq)NSbsF$wMDX1$j_gjbTliq}sX&Q~d<;@~YE4>`a&Cv)qv%D5ryLG$wRAk*1D>EI-UI>mgGvO;UU zxpE-mHya@#Apn4v>~udG*fKob0!iv{dDh}HJX}zwl zZa(8OR!a-_61gOUyCjQ?BAo>91bLs0pNjjb`;}Py^B86&YXUK6#v-$bU#qReHFs|e z0%N0jc;vf660<>`e=#QdWo8eENmNfylo*6iP^3KT0{q_wFs0>J51ZH+;|z^pr{j7E z4^(Slz%C|Ral-0&tv!qinDuk_SUDwrc%c$#baR5#zKWd|+0|d>)90$ zv@8OF%bocana&_gy|niD9{)2v8r!p!Blcx0FS0nU=Vc|4ZktQ~F?$pxy0}EP#-AV& zG~Z8#785t3@8IP@mYg7%TL=P**+Q>1-pQ(uimd?Fk|iD7i|+`f7i>1j6~1BFtfHp+R%Ay%R(R@3D{LBrwpxc+Q}m5=gF zWz8o4hnnqjqP!4g8M<<5Bu#vAmihPuhpR(hy**8ba0NkTIRKHM>YFF8Z{-d!KBH7 zeRAv5#DQGU1t@gr@rcl9v`z++EKG)sO5j$q>mv?}%|9pKO~;me7BH>#+1vq@;5`r! z-~DR+W|q=Qi2bEu*Y|t?JvP#MiHATJxW0f2Jbm)^=FsB!W0s9!y@eq1+R;`G-^MOf z+EATFR3l(Ns++SrH_zL{H_L0OXHIk;`&fs?oNjZmGVspU&*qbr!h@d8?8!hY=x*IK z7B^mGM=r_big9#X*`Es)=+Aa3CQB*_l>+-|bVHnGrKtU<>g~Xr{^K%G$k`^uQSFF9 zn+zH*^=-2N@}Sz{42pES^LcHch?*gTKFn$@pV1Oc0oV>IyX>NRROW5_lSN!yTughR zIPF=>_ed8GeG5{cPI%DbvDnym#|Hn+-Sc^0_1ARUv9TH&8gj=Yb6-wC(J8(!+X5MU z8dajPf&u_86%}AdOOw&2NU?OdMvq3@40(U6yyQ(yu&ls2 zBPj<;Cw#q3zUH0r*~$J2e6d$FDdn*>@nZg4B)}PvkC9yYt8^NE8kf4Rf>e+MuP`iP zHb%$U)`YX(fE+ld`Q@|yufYAd zah6yFU9Db{rsEktas=eU{Ce&}W-|L7Y-kANjPn(VvQQYnx=YvvAyjHP7n(>GJ_Y;F zW=u-h>>Uh{8{g8>T%G^JolO`ZdARG9M?uC~+Qxnd>WuG8;^_bLMXXh4D)=dfI3+UV z*P$-ls-`(u(VeQv$0_jCfMW?LidMrT@!98B2_7CA$Mpv>4c(BDA%$jX`25sHMtMRR#IOsMQ@XE8et3L1%iRtc@0o{^$4Q<=-${~cQKoZT%T{tPCFs;ztu@cJ3xMEk0 zDmmSKmWKEa;G+zv6rih#mI}!=yZc{%DP@^~FN=QX;VeYO-dHc=e6x%tQQ3KF-r)*? zn8#siXoxE=F8<0>a%7bYN!JZ-Eo)sMu%43 zvyxJ*6#*0FHnI+iIa>zvn(V=n(-$WfBYY0)r~g6-mJ5d#xU#Y`{o{K5ICUsNl(-5c ze8aaB`y?bJ*P7Hr3f$auCb6@6H);D+*r?Ki%V~^DCTX+s`7l1M0sCD4iqfUsUC#^p ziy|qtP*BCWyzZTMKrr2pwU1Y+v(yG&+tnH_y0`|rU>Bb2i%ki}Arm@wdPa9YO%O=o4B zGK52mVIs2Z>m22#bqyVTF;)!t6-JMh{kjsw@BI_o!wT@K9KjnoGoL=C`dXWL$8rps z*M#h{*w&T!gUY#}At*EW;blpfY&^Jk4^IF2W2ZxE6rHBH5ymFz!Q0d8A08-wMHx-? zs)?Ntjn`v2l+NZw0A^z@k>FAoKGUDW&DB-DOpDq|yzJ2fmA2|3AxCwC#j?NTI0P;> zW;uZK@59`zVsUBVjerjy|Fn-j?|OCBMYEx1VfP-je?vExhC}w z`|U)`SnNb22=RoPT@QGB&f5bL0?XOAs~fnUS~M&vIqp_w1H2Rp_Z`sG)J&8`zSHh7 zR#7i}AQLCdUUy|yc4u+D=$IagQXz$!b6nJHc%8~PNjeRqeD~g{T~WO-Z{EkOblbzU zl$iGCo(9NN^Em!XJWO++b#pq#x2(_&6K;w$vm42V1a%z*6j@Ys(&3tY18N)xT0EXx zWiNhV2yvVe0NjR-b8R4V!nA3v__>Qs9(A(Y{<%|J3!QPMXi&B1@Ask3e9@S+lh!M3 z6;>7u0_TCAIDxLPhI~G^SHi)rZGi-$A0s-GKVaH@>Hs4{{oE$?-f0!)S^K}iD5kDZ zK%`Ew(p$TupN>Pj9l~*4Ku{L}H4F&a2%kjsB~7CNI!(Hm)K{+_`Sm684&$<_hSK+@ z>rG_l7?OagK(CcOANT%RE6E!AaRqheJeGz@$i&;><_QB8&fV!Eo3=vR%rw#u@3#4m z9swiUe)aEUT_{p8!U?TVQW-M53%gcYuOllvFHrl|(-j02n1IseR+t}OcI}JzF`TH( z${?Voej0!B1^l^zzM6rJdDf9y^QZ;1Z|mb`o2MVGtlRtE$v~oM2P)Ag!$g^P4$hVy zOUx^1tID7-LO|AcPeOYLTvuRq8$A-U%R zD`R730i42f;XBhUAyYC+HQ6xETYEZ&h7-fzV+I*DSZX)@9wd&o{LF-y{^6j)M z5~gi{NiS7|ZX9GPaO>mM1VN#Mwh|MFI1K-pp<8{Ig-F6*SdCAWcN1)cLUj|nvQTAP zbB$rc`D&4Wz~~mGqLKv|BI+ALA!BF1+?9L+x4tLsK35AN!)&7R838l5uHQ5o({uwF z<21O=hWd&V`;$G5-R2OPrgG;IxAr$<8s%l$^_vT`&E6Q4nB)twpC1`y5D57YN&DlS zQevT5HtLf<((6dDMDWkL?DSnDxW=oeAJV7mJevYiNW@LMOAQQP62O`Y zUYVcx?X9DrCi}h_TL{#hR@kcA#4Gprz`%g;!$(|i3T&3aW}lEVa-Y30xlQ`uVzwyl z9AMG&_s={B=uDh3VyEQnmC<1`objEL)A8p%@^GL>f`b!qtb;KhCbP^npEWnnf^Uu2 zngg$?+$XEdE$UCP^wCDq#{X7p@$EQka^xc0U9>qb{HJr##wEbrr(}?vn)&3Kfze&l zF9S^wmB+9r5x+Q@w^`6OwDZkZG#vC*>qTMW^s3LyUp)yht%VxCf8kU7P}m^t)*KzR zo`1X5{oxD1Wy!$DV~??PTLH(r(`}? zx11i+X{$2czIba$$xg5JDWdU3!Kd!4U8giJchP9G&o>q=|F~Oybb!q=Bq=T^DRjp5 z7#=Zdi^O|oIbxKP& zy_b=SnWmpj=M+yd+__;-J89tFW@b_rQ|gky4JOK#YxFZ6Q(aXZmI5k-_rs6x#y>w~Iof5R3VgBhoxbEPS($$M^EX&(qpXmSMbgp^L&ohLF+4TT zIq`Fsga!a8)}a5pOylRbzxPsOU*{{0cEXFI{6?FqoGwZ7N4)O$MiVWOu03E%scC_odl9Vx)Y_+BOOhV=bM zQ#`^F#&>wGUr(Y=Xnv3*&e7|_aXoZ@_0a-1cSy}OF@Q<@w@Ezx-PPn>hKPuMMD80d z;SMvd_}S(w&*>_C_Y-ECPk17odHI#NTaE^!lbQv<1^)aJ{xhIJ*ob{Mo{2-}<5D)t zB;#vWQ^en1;)`dz|G=m2Lh3>obZvTuyl$2Fv-V1}o{IhZxAnPhp+$qM>O`j&Xipxo z{Vvk>I&d99*?W8|7|^q(oDUph6ZdKfjbkj}+&yburt-W<|fvxxyI8MUNF- z{PunrmUYQG#FD2SytTWtF4%{wRS%a;GSk~OfRpc>O--jI;^M<|KU6IDNle5OU6hF? ztxo!u%ESN9RIPHR9Jp60T=kE*dKQzwvo{u{m3)NdVBKvl&9R!kL9IA*p>c4;fT^1@ zZ8*DEG*o{p0zgk3r1g)Qq{QCkU%$n__pj*z zIO5!f!h9kD<$+yeg<)P;`yqPfM-h-}e_g?M!o?k;aM>Tcj)Lcz+p7Oic z+J--H)^gr4-@`7pggzN*R1Kpnnl7jZ{yZwf{SLLV5fjLuOJe5eCt?<3{(bv)4fe}6mqqv{H4-O#|nJ4mai**+xPM6F7^UZw+pgAMq|FI)Y}gC9v6^SCrdK{jg`Qe zO55ZLh8Q+=X59?&yg>Z=;C7qX5BYaG+Aq&iC7l_j3TkH*n%rTbM*c|9ovr6>X}hi6 ze*ET1x~-Vlbb3gK_5B&BgDpWSH7;IQWPq>k$gOq6VvU8}l8kF*34>d;)Q^^5ACvZR zYDp;4o6bhsoO@WIj_G~Z8;gMY!$9)u!{dF`qUBPSSX}Ci>s)Ifqd84)86GYcsQh#o$!RE8jbqnWaQa`BynN*gLXFH*CyQ ztr(_L<{o@hI+9<#j7u&+M+_y}`s-1Hfp`*W%syrKWy~?V*^E-93?SY93n~xh8fAjI zop*XKk(T{r$TfJNCtf+W?P<$^$Xw$j;OQ9v$E8V83+oBpQ#xad@v}z9zwkFSv@Mt( z){LB)9;I?tI6?+G*cu3x_JUx+F#qfE5X{xY(()X`YkAiHQ%C<<3xA85l_2S3o z<`6YO72(dK4rH8<>pk&XpMH{SWk@o!+WN82Dt$Ye5W;rr_F=%Jp_#VNVX^1R7GThT zEo{KD0obKmE%_J(UwYvms7B3{73y41|Q0tS(wtU_+Vj;A)RC(Nr44Va zmSgz)?9Zsy${}b}GYBRiB>QW{#M?5!x&?8 zYqtG)hzEM2RHo{8gXe3PKEmuQsw;+tDmiRQ$vUGO;bl`%QQPVyT{^HZ_U9av4e+)r zkc1Y#4P&Sh!-7if?My_?>_k->kl~a3`#|0HbhjI7$LhfX%hD|c@8v{+wFL7P%EYj# zC2EAlf?VCNq{-rzmOMKdrQqV*S_O>M!B(_8^8|$HxpzT9BfhNqI-hQqFl{zYUpQ^< z%b@^^$N`Tqj3ocqZx~O-Qk2**e4Sgk@_WoV9=>39q^?z}@86)_RdIK`(r7j*3y_iE zIA7$?e?Jprpk^p&w7x>hWXWvy9_G7i!heN|mZMdB0#7u{Z*Nv_N@$BI}+4svk4`yjD0)2f> z^op?B>C)vZbuv+m{%bN#L2_*r3L_cB^sTFul*}=xIbF2M+34g!={BHClVi6M7SV!T zK$4)do0AHZi8O;DhSR(bm^G`@ai`%S&SR{UkDJCx|8`B}$8R{+20W{{*Q$vgF2nU{ zpWd~tx2Swleu|i+hB_IXLnSx+X-BwnOWAjQpxGi)yNV_=sZy|ZWIZL6jkUpxb?m%+ zvUFmIo*D`45vHE70#R)z7#Y$20Tmc-A;KzZC`C|+StWQs*WcQDxI2zBp^P-#0*0Mm z91TEs*Fl2QEexCdrZj!52bs(1NVM1DCQ+AYS38y(C$$B6N$#F5UN{w9q+&+u-l^3* zYmk0=h~x0jsw2EkbA-5~bDzhYF*A$vr5&Y-+)?!EOB4W-l9z*O`gkYGE&PMqv(LTR zMo^js-m?d5F}jO^wWS*HPRX`EsdV+ofB;`j_@$iTWM-QA(}U4TCZLs0gq?KY==4#o ze{pS%0vec))_Iw^j$i$@-Ft9n^ZQk2>;(rZfAou4O`k_b5W4>GOr-`BrP;qefS27L z*Sp`Ivj*feRUA!~nc*>+&ekp_$SD4U?+SlKEABM7r7qq({eX^7|69%~aeBO)cy;kT z-g&rKLd^@?WKrvPTBx7*B9fT#(g*4DV8!kYxL#@u)7;c87+fEuT5G*380^(PR&AV9 z1&vk7N?@?sT3Twy&DGiF=#XjG{VunknKd}i0O~5O;+%`AwUhxt^@6pb$J%d~q;|?# zmfRI`|#`Hh>~PH^H6Irj1j9y-dp1C&bnxB z-Q}eJnx-AB;QwwYMhNb~TxYkT1iZJ?B4ixlffo5$JZ_g_w7ed*?hNA>(E2sqxOhA{ zQt`oSWOnSiB^hqteaE#G>Swj}ce{o%-sUCGVxhamdd!Dm^l6awiH$vKU|4Z;Sg=42LhnZ6H)Y~ zCJOzcZoFN;#3Gt3cNhbda>~9|9}LG{3JqNW4c>a=12j|Z_FsZDPC7Tg%*A2Yc`yW} z^tIv^wsc&HggqXA_bhbnCo1g@VR^E&Erfg#QuTIgTCWEB;(Vq9HQzel7+)RxH0P15 za9I;*PD{seG&2Z)F@aftQOkf=Cv_~p*urwV&RIBu_MT>GXz!u~=SSXX8_UAO0L!+j zq=v5zrx&9|c+ zwn%f8^0GZX;Yzqu((YhipLwm9;}zSgSsBIF(b=Pe3e@@{>!-hf_3l_5m`SUp0KrqM zI4Yh%XZw;w%3p}wvGST%n>zy-)LVbJogZB-Iaa99@zh-sv`zj+tD5)>swKQddlot|g=Q z(qU@dSRopwa9LUQU9f6Z$cCHh8#^x9>Po0H#5!zOzrKaAvv1|QwROyi6t!;M+1bhI z_}hR>%{0|#H*F2rBG6XZ=$m!5{FOe?ds!(gBt*@R17z^OLzR=6*OgFhty|&fABLNb z_IKsIQK^H!D!A2Sg999M$CJ9J>6mTm*uEuA>Uag9e)P8-l)Jm%#c%xC$I`(#eQ8M@ zuH~zhHgEp@(1c&t_w=;KG;6|d`?R$og#7}a1a^zR+O&C2@qZkhvH$Z8`EbYrRYwwv zTZL-?372)t*;{#uW}45<_i{f~ubfi>=PTpNgdE&B6^lZCmbsjh-fM$WQoZ|Jy%o3I z!ulq{yFBeM_{@Fja5EHfYX7VteCbX^2pAOX$We=o5ZQB`a|ya;O<2eVVjKNE!ro#w zDDy`vA66ItJ3m!rdiT*?BcWac-hdW0ujL0$pP9uV63pYg*c)N9c#;sW_P<#ltlRFI z<18`++Hc(vRF;yx{cOHwS?Xl)^M?-~vbkb{1>;2Ax#S*WA_bJ;+h|4eiM}mVymC&? zyH$+hpXlH+>+{SN2M=30J2diNwwC5!mMgvjan(xplkZGh)Z;iDQ9pzbKA53Ssa(Jd znQnoP5V?oc)7WIF`n`Q%qqH?uzO5+p#pl-fIZ2~U?NNaD^3W&^!;~hg66`!+r1c!l zn{pWSIWFqd>Fi>ZO(y6ohf-SpV5DAlEb4n>h^4_c#G>|&fmy2d*>k+o=zUOTidZ30 z(xe%ho-Bfa7#0yTJ0xj#nXSfo2(UcF52L|EDQEOjM<{~^AKf8N!%WZP36;}KT>2wh zOk?5Hkc-J>2}#LI|2f4li?GUgE*F#R+G=a1QaC2m%_E1{bp+w+CjHYdJW-Z zd>r=yew$|I=iA$_PcTkKu1^on{g+qzIvxuQ{Cr{XJz8i|JsS%8J8bFkMs4TX^_v2``17*!65c9CDB- zpo40Ym(OS@_xPaZHj#1iz|5D$Z`f3&)S-iNc)2SEgSm&S2hP@@gjL+!&3p2P1OgoQ z<-8&l8ko52XfCiy-UECQ`H?Ap-xxg@CA^Mzj8zka$77YMHvWxQgbmxapAkr1N;V$pD%~m&qj%2oiE;P zZFTQYo<#5Y`^b`H6D+Sj^I>COSWed6BJQAK7O{an}}CCZg|OGGb`aTmY;kOZ|4|W{p$Ok)H1>tnPg@3^>!&% zPq@il8A7swU?Hgzl@mMX->7NS?EPuxB@DQ}Yx6hyd96$h9yukY7WsZX(l3*5;oItL z~+W15`!WS z8}U4=rHPXH5*F@ZNXD#_*SFlx!W_HFBq{MQKAKu|=lm@(ZGJ{K8*%P`efW6_b~^=| zsO@p*X#^vjq0h3p2(4qU3){)OTBkGT%W#=$zh!Y0I`g07r_&Ox4%>?x(9?PSV8eI5%wP^2^Js*c{eY|7jXr z{q(gjmZN%{Thy($61&iZ0!mHbt%eQhgzGfB({P(i5CVuItQ&J1PfFwC84gG*e0qgC z*~-zv!ndW}XU1%wJwL$qMR(~~)U$6tP-!7;jPm9p68tjIpY();+2uf9pdczO!jZOK zbHCQCw>6xauUj-OYzU%Vs)+bIH#{shI_u@To|g|=Wl@a(okHLltksKW6ML#N$XoBl z+QRKg{99WJB){ zUVSYedg~Rkz{gIA57`2xE<$s{j?TKm1e62epmX$}k z5%rLHLn^wpE+aof3sM-q!TN?(<_+_&lK)LE{rW3osMH#QrxC0!;bnjk6(w?;w^!`(TD}-!=2k6kMcEUnGtWU8Dn1J!j3D4H&O*|O?Z|) z-~J8|kFP=kX6tMl7`x*rl*vLiHa6{hz4v5N(F;;#CxyWK&F|rh76^c>EGr?gGF6k< zq3~j|)RY6~Q(Qd#DmTz}JpE!f2C^e4(2ERNxL7MSIc^BC?fxXC;fqE>2^(P4i}A)e zt4-fgpAF2L#Zm&YH9@a(JRpE-+&?Tg0H&z}XxIufSu-wKEh;nx>>CQfY1Jz@0}5^m zxJ%0QczKPCJvgF-{-H`6ug~u;SonI?3bNB|p|Cn%8UO;c*WdkAY%E(Y_VQ|-D z66Mtoa6bL}X17du&F1I&(od{&OauM>PTqH87w3b-+|EH?yW9mt2!;6B%XlFGO*>jG zO90(mXJctuq%cjr_ED8>kc*qUVfHWreCmyd{iP)q_Ou*|FVo^M6?!dalO{GtV6*`> ze;&yfbGb6_)L&~Txyw)I{oBA7j|!}UgM*d$_=;}WlCJ8wQF{k>#`67m-&eNXMoCvy zS68msWCtrKuscY29#+YHTFn69YK1QC2GOuRmOe@A0M*Vd8JDp>*A)A-;V(T&@WSNI zn}bm1?MDIl{r;h8FEwYm9n%pSI(`#BtC7`N!|!?u?NO~V!#OE*Vlo^Qx{fO48>EeA z=Og=9Q!Ijf8$;?Oz%tUqRhFRAieS=DEg$gi`nLSi4;;X@PTzyc3;^Wh37#M%ePkwn z7gii|iDN-7l+!R*2&8%%}jv>G)zMFhhQb@C~iR-r3@LdO(+7$Mq%k++pCH$rh1fc~()%~7-;6far2rI{?uF-Y zl@?1I3s_JaKo?uwAsMn5w_23#x%p2Ve+=oVn%sDvjcW5SfB%9x@y9jA+nDZqvLntT z^$SyR00@G#=H3Dky80z)JYD_U zN!NcAw@@JS%sDT!z#EqH1g{DXjHmPfxli0aG-M> zLwx)ZA^+uvrI+7#0AZS45*Sx;1sUSKpIt?-HI2-!s$@fL9%m}x#qQHTSAKZgXSod87C@cV`==iA2oLY?$c66b_w_w-1(jtEOObge~V?#5(#xGpZz=yuR&Yy?&+bo zA=0#q+K>14_XU_m-g$dZB*+6rjD5i&A=DKiCar9e|O({1PjB5qexORH$^F~5k2 zQZTxFx}|9FSa;sV02^yCjs$3jouSp9) z&_$;=P0bF5Iq{-@-CkM#qv2FOKPfTDf=C-b#DVty-#K*;7)n`Q29|B4^Nns(@wyHA z$xvivm4l9%e>kvG3OI7bT!~B`OqU_UHmmv}HcDpoUTZUw)rj#js1T>s^^6elTz~W0 zU-zyP|K7`$u&|gfk)~<>OF9S%2*?AKAa|Ti5hY9P5EQ=<(qC2CB<+VCH@O_UhYX(G0Y)9#oH-FEXllE*#P;5@SRVcz|31O z{t!z=TveW_&c;;5HVumvioEs8x6Up00V@(62}Y?)fDjerZVXz{>(psW zk)S_AN}w7`Qc_YK`*|>!6%)mQUkdYo?Pa}y#;?8=NIKb<^Jo1fx-$z~oEW8(IGyN_jAV}&N4AMbqB>SaN^eFM*=L#kKPw!yA zp}#J`+wU+~ey$hbD@)Bepp-ek(%I;F)b%LX>0))=Z)(a$4|n?_GYOD{(>g!*_tK*i z)KWU_k1cA5U1VdKpz?bM<`WwJQ>srG!!#Tuz>Ohxi9HCCYU_4`2V!o__2f{|SEmL7 zqNNtQe-Sl!UYUmNDR)uxKmJPb*|51fHQ;Pu9+alr+($1fCo?HF7@V|@P9doOG6`4P zjI5$uONJLktDI6Bv{L>$kfzR#qAr(Whc^8g1wVPLWDBz%pTE2akH2*N`cWhur!x61 zjslb|HK4&FpNL7$FCy(=E%=tf-kR;#>GkgOlhB>`$Jr}XMTpm;F(oyKRz>n#pk*y# zsON8mdEKwE*ZUm_&y}yLANVIZsI;!K&BNMD!j(92HOE|nMP4cg9K7{fvvRI8e~)EI zQ0w&Zd?1_INx^?NO*-UkGIF{|ncl!N?YpLVRQcx;{P=I08wyaOOFnHPhuJ@cf{@`4 zUXEKId8es8Ijii;W;?p$NR)Ke0Dt;o%bP%#5?s^K!EdjhhpF`7KwzZR=0BQ}kQ$qX z>|ml_^ow@+t~3#gD!YNPg3PO7(wAQY-uALd>(pt#`x5fw$xB0FN&T^leTm^G&5e!c zO`=lBr>3)?sxBFK4m7;Q9Jvz?Tl#9I{z}gvP?de2yC70fOz`IT%NXae|?vekZ+#=)04koH^7Y5k;X-o9FoEQ z4m)gYP||+pNnNvT_B*uj+XJWbIGvyIHFjga*7p5$edeUG|J;fqs8~{M+F&8EP}lw{ z9r@b>KSo=*+-bQ13Y5kpiuh4+k(n67=qCBOg5mC5DP7 zV=TmfPqlc4?ZU02&jujX&M*27XVyGpz&~F0IQRCnH{jD+xwKpv1)@eq!ce^_N87K0 zzn>9f&Wjf^bQeEf!_}}2I8-aYN{c9ydBUv`Hn#r@$6}=EGz=mT+1;iwJUU$wB~)1D zbWoPKNzGgf%p?49Lk30WQrqm}L2V~+ym3FX$S-dX3UlRVRmm~^YeENAbG0r8Rc~4K zHYM{2dGR}45tr2zP6(s$&krt= zcz-acX617(VQ_7{p4}!YVrE{BgcGNa9it({G##``vqwkr@4@m@ke>;X1zlzY+=i|Z zCK7)4ZobtpZvRzm;N;|M_}~&!oLFCYdh>?6@j=j=H*bF87b-m&`Oc`QriWpkZTb!l z`2|4u=|in06Vllccing|69t|-#5zRMAG;6|Nk>&!aGiL#IW8mWvC|spKA@|!L=zRm zW?_0_1v>sRB_)f&Oa;PP-RAfI>$xYS$*-rA>R$xGOg7oq)he#r3!vkhKVqE{#hhB9 zi;HpK9=r3E-NNg1YApBXfHr)37$*hnOqQ~EVjQ@~E~_+HqY{T$MUICdmVsW+=NlmC zi>6EWK=McyG<(kL9YA)Q+>1Rvrs<)Kyy=22)Jgwu3~ZIz!2Uw{6mFh{ccD%IqiR+aruT>jPll{ycce1;psb6BOJ&m+|+^KnTgxf@u}QAIyk z%WqO&TJakAHAMDimWOU+k++wyT<7s*f*i-7SGqpjRx{GvI=Fw9C2?2q`Lp}i zc_rSMwp&YeEg-urdtRbBelI)$RMCTd*2t$eiroKr^1No)f(Oz;1>WIe?RAMTALk+V3kHmhVz zKv{Wc?ETt$$_I&!Ybc*3&gE6k|E}Fm8f~cI7dO1JBKw89=K#G@@;M&yL^?K~HLFf4 zj+mbG`Y`jGO@0rsUJ^|<8wA1?XeKSc3f@nYN}`kwm zSiZ&fAWEn`cs}3cJp%OPqL}q1c4(Sq*Vgs}9K@|}YcFcj>Jw)F!y45;xjB9qD)^rm zAJzRE-?e!nE@c-!yc8K+{O<6o19k8lz8BA~{44rn7W|to`pYVXa=G^j@LMmyr4d>8S#UqygUh#ZU zy%PPMQVJubqzxHj`>#je_S;k72E`?B=Okk-2NegF`z-k-uP#rKG>s#f?2dgYzr0Mi z4!OTt#mRoeCvo>r=U?8j{J@87C$;#OgeS(fN8dNcU)JBE>3>5XYA61P*ZCIqr0sEv z(Ev(aJ0oc5r3Z#Wc~B(VfpW7qulv)>|1v1AI25^M5A>A43pHpi6{(s=bO3YZV~4L3 zj5k@$%Oy@KE)x>3ty)rG^S$v6oA{h(UGfL7KJ_IPUpBtA)$|klYh}S|nCheKoa{8| z>6G!U_q^>?(!9frR9F0Fq+RcS@Ykyr%#Wx4FidrMkjmFg>AtK{vG^=S$P*RI$L}h2 zC8YWTCai*l8{ReQ4>j#)r&%fhi%mZTmoGOl2i+B(3$y(B&e{vui3@7)meEWUrq!W z3aTaCPi6Mrgss-MiZW?Umy#N`YOP6Q2~_%|8!+eE1aXUdt-f50|nOc*8}} z^*S{)J%XoD7tPAmkI(bG>da92@rKin2rbp-GGozIUjfGG%H+c~waN$u?D6P5Hin`)uJE=uyWZOs z{3LFx?o^mgC1lGY3edw<;7anTN=A?n00{6A z1p#9cNCZ^9iG%fKOdgS+JA+3@~Mj2O!xmyjQ>zL{E*xav+CnNu0l86{10bO&oAeHewN3y_zxw#Vv;db zB~7OJiDn;_Qi?%hk~&p5`7a%nS3)>WeuXJ!ONUhD$*a1+{Fae~$(3$_1nl8>p|h^b>-|(r{?SA8jZY8Jv3e1pGmY zzP{1X@sUvh(I7A?Dl*C&^hZ@RKPoXa9TCGI3sqr2q{1jHX!uu$$w_UAF`e^`ciNM& zl(b&*2PuH=6M+&iEgaxAzNs|GR$*8eA08}OhA`BM83Ic&-e>jjsStJ1{ zU|39>8$>dk#lB62m82yEl%(p#334>)s7xh?fk*}+a=cc+4pL!6GEDm25)_lu)G2}# zWdCRqmA5Yj5TVYn7o#FvE5%+4D_{(gIVGbRjs)sNV5lld2II*nN;oFNGC7?j>xkgE z3dWtRHG_Ag$T+tC%ics9_tAicl@F%~Vm*lz0+DTmh&k6~;gaMG)#SM^n}?pt4?o zofuYPum~bxu{WT?e+F7~fx!wfjP+H?WOOZ@4Mx~kL9R+oaUG&n8^%WIR_I{-n~S}M zs~b!m-DflOX9m!!Bja#ZIe>GjYPKuRS!Z(45!1_@F7 z7f-8edQe)`m@mrD1PCGlcHBHNPBZq@eCVRZTL)6Dj;UT8f0@mhR9?3Z99m%19{t0l z6A2Nd&|y4n(i~>Bb`?af#~HOw>N-wgHRNpop6ZF5`N}$Wq)cZ2)|zOxgz@AOW=ai~ zs|5zpi&GOy850_y2d*6y-~#~{e{5Ey{eOkcKKpR~L(KYbn`^cHm}>ts>$xA~08|(M zb#r#n-Txt}viB!3j9BC>fT?1$Z(|s8v*CS_^Y zh-Pd;gYuf$3P_+-WD->{N#6oo35x_cvtyFG1Cmq>;JoZ=&k>`dwx0p=d(ODkpF?1N>W0RcBg`Ikg4=Z>XcBUVu~wc z9QC%sQFSS4!bV-ml9A~!h9P1Yw5c+S{5zPe{tdv0_81TFD0e>j} z!v_Va5hqc}WLY3h1<9xjwgIG6QiB!n;$gaVsyspVK|+qJ6Kio)4s)Y28m|Edq-8Ec z=_nPf5M}*O(xP!cnWjd~@Hm9Yo)JQJ!-OI=<(RxIx+GmDjydUor5@eF zCNG>-0TY*5IDeg1!7){qss*-Dqer_dQ(4E*kry1`4SoG+Rx;RX?XlFqt@hQAiS{3z zg#1a?e}pbB`sY6iUB1|VpXI56{ik03p^1SJn^nk7mT0s@CA**!&E&Tm$|BG%LyA;N zkdQn`^BN!UAg<$8h;514Xt-z?h+82MMS;l9FGj7 zNII-w%}NyxW6TjeYHh>W21OQOMI)+!1;AG(Lo;xCD=)!RLh023HaFfbMTHa0;*lEp z_EeQ5NR*lZVPee!93n%AECB^US41H}Kkj67Yj*r}&lFbmCWM>CufZgJjxaTTR3XbE zWqSq;l7FFeav13_2FY}BijxACyF30rrN7kYQ1X!L0V1s)Kxf) zs?)DmLvO*6+32TB_Zsa=Wm4#^JZWOYSH%lDEgN74`UGn(qJSf{r>+Oxn2&aA zx?+jl>BHug8W2kk02WBSNiz&jlc_Px7k_|w(#KXJqEsM3Fr1+G{=o!{F-buTe~RhG zXi(`n0ghCTfks}EFwS3ZhRR7w=AJrEI_x^+&S6@OiDs}(?7&D_&X$>6kmTV8D@5EgOmjHr=W+Hk=p<>w3Mfeii@BLe8Y1q= zrCej##Ww7*w|zM*p}R-h@GP?`im=Tc6!cy!H|rxqSl0&;|No_@=70OYxqB3&X|e!R z&aXkK%FvC7ETGwBs6L)U1RIXUaSE8a8C<6;jjO|apkSneKAgq{S|1JU+}4feFq;DP zs&P;8*Y2@r)s?CYkx~*=zZRRb4yRFJV67tdI$G?(ee~za{@?Rl_F&sclP>|a9 zr_R-2iKVJU8Uq`Jf%Z;e1FC=y7MPkBqu+&&1lNn-r)vTi8p%f}W$YL3rgB5K2XL#{ z3DVV}jsB2aW^cIme`sH^iTqCo!ahy@ubZFN9yD-7 zK?;s4Na5I%pMOI|Y6WBodedKCULGIhf+PrsJ=}n!qZk&UV%Xk50L4#*$ix6vq=R$_ zqmv`)MP`W3zN~isbZ|jW9y=lOEJyWnQ1vsS(-bF2NqwObA(S$Nib&w(AJoZ^q}9s| zn^S`d;rT;29Hdv3iUjJNkfGZLS5+8oO>-!Qu@ZKG4u2*JfW5IpEi`dOqpcWOoh391 zSc0K)R%OyNSnbSJxs;(^Fr|Ohh_mz>)CQ+F=jT^J?X95bJ}s#Kjx6Hq*I46I30mA=)?>Kfndy{C@KM+ZSl@b3=tp- zz}{CzFMq`wJqA&85U2_UJ%Js&(xL%In?g7rda~6Fh04^y(sXkEG^=rR6{$- zOn))m(>rtN71|&~AqIR$Y|tQaSDRcs8FF#=@aEIUjm7&$MTA83_6AX!(E~9|z#;+` z13S_r=NufGm*-8sAHyP3!1TWv&O0=EN4fzrm8)a~qSU)Dhi%tDY9lvSP-j0@l`GOt zU3k8#Ohkr2SQe0|6to@1#I&iqP7rA_!3NtO3sBH!2Sit{0_i+bN&7A9U znW5>_{_-XH^2_rf{+}Ge5PwLVWO^vD8voDJ!^K_K|8sNx;{Sb?=R^FzaFPH5{A%6% zV+rd&tp-)G(MjJl-9`OW9u``K`J8ogPlH|whX&`5GG1S2$;HM z*c5;`#dTX!5y{3~N1b*^MN3vN;xm#{V!w|ap_T1sq7YJ~r51+#e{3?)OgsF^E zpMmlw5TT~lCqR=Sn18Cq*#9qq98)x4t;KR`(HJlV?hgp&u+181??VDPCN@*cVH|c4 zHJJAg4B;4SC zFtZvn`+ss)HQ-k>qg*LzXvVnj|J^X$hs1wSg%qv5_>a)p&3{F2{ol>y%l#jp<@uoa z4@m$4ew{E_+P(IJKn!*LcY;9N(Hf5g(O`dMEQs6HCkhDZqqk-OA*Oz<1cbEPG7=D~ zI*g;;gpn{#wLvAFK^YG!{nr9Q0T2NtLAY*xG4uL!1(c#;c87<4D2e`7ZA-o?A~{e) zE1Y)JbYUb6MSr~xG)`tUiI;GpsKyul1ko=#2Ehg4KN%KdMBV=fVKKS_m&rb+S9Lqp z2jfV}(iyT2ET29mr=!vSQ!zOlCQJy)X~a@>!8oR*2}Dnqcf?`BQGKLrEk@uNK)%G@ zOf@!YFZMWBwCeA@;?$ht7-@zBmO>pNc7*1%6z`(1LA*56epw@ zjHk&=3;|XX{}Xz+>gIpBxqQk0`aI8v#Q*xz1Q6XXtk$D{9NPNN1OPQK84v$y%6wb| zkki+viGTkYMsSTnfSe{iavP9=mJG%K)n2Q*JlDyszE#p7VBg}J*jzPzaB?E5h%OoK z&0rdpKwInmi@8(!#SCKBc=$lSxN+Cn0B_XN79)Kqv|~mLhBy;hBP!(1qGtBAqZ0TAUMlVgG&Xi*AePW>%Q|J943I=Lch3N=!qe`Xf5op`> zIu^K*Gj$D?;`GBIPnuGw86wHzoB|_e+5_J5dMjE<=qk}*OON*y-m(nD3{{+%%N2gHA=Dm6I>u$uk99^mZm*$_3iuuw#e422t9x_b}%+l3Ni+{-) z&CS$mBo)rW1xl){PD9k8gAj&f!{Rs?!;J*#v>M}75v0>~`1Cor#-rE-X=7qpz)t6m zJe_gy4JB*XS6fTJ0-R=WXl!uMSit?Gt|HY97aLA9)6d})BRDtwSR+)agNW55iCffU z^k_jDi^IMu`c~PR%_l>`)x)U5;eWn00`or+&*z+4uffpAq$+A*+jtCBJ$4d)wrj@n z(+=8k^4xT&t%}q3wBs7*<8gcc-w$0^7l@(-Y*o72uu`a5_{ne^AL*OX zjs7QtPPE3O?-5{KF?#eSW15P|FpBdNdRet*g&0@+#;2LC!=1CLQSYA&i+@rzH^5T( zrr@Vq?2NM*#c6wv72q^a0z1ZL06sl|(9PcDnJ{Q}d<6X)Y>&IKfm47L>e}kdt_C)j zJ*^A*Mr<##1LjJI57ZsH&{l1J&{rE8>YmH7>g!^^m3Q&#z@8;p^ ztegMkD*Uql^Rql3;{G$vFn?Kwa`Tg5eNUgZ+^O;uTl=F5iL*0xue7egr@romdc`;9 z>8q0&7z4@C*_kntjr1n0-QI-i-b^w0jM;hgg*OIqV`vEam*41215k2QJv&OnA&!`2 z=0YO^W$h3OYK4?(3Q=(E6G0Xvmua1Irg8O*L{l_Ih0$n=;eI(6w|_gCe!v=Y|5tVW z)5VyvF~Eo+0y5l%@w^8Uta^>2qVEb4sAFSV?o##CgCh#5p0l8#VS#$0je14Q?Pvxr z7BbDaRZ|&z*;tj_Uj3Mij)kv#L|wHksdd2|*B0jd`GsjdFVpBa8hWh*NA2OUMX3u= zIOF4lk;xG%DgQ$vsDBAlYV(e6#PUP0=+bbUvAvtLLCp?~6QSbsxltzpU*r1Nvj?tm z-srD(r|YeAb8o98*@01IT1BKV;jh9lSfL3i^7Ssmg%o17OU5m-7uM398 zg8?xbXIVrSp-J0&kYbR6%|^7v2Pq8rIYzGY6xbU{^wReK>3`;_Oa1i3n)-qsNGt}O z9UV!th;+7k+K|N=DL_I2DZ~QO2h)&-X7)MnSOn@};=ke5RAv7Ql3|$~kt$FO{-{2x zvHzXjbTvj#EA z2o7+SQi);&4u9}uSSF)#UVt1TM9GLk>HsiU1`$X)qc%0~A%&P{4HU4H&XTsH0~1U( zD(Gl00Feq=7C;qLO%f!agfSpP6tI9N2#6jUO)5E_HSnjX6U6yP12KZ(Jb@G;oTz_k z@OgryY|M%Jmwk~ebt3;^f8yy1Crv|1kSJB9qO!JRL%eHZtiYEUH*6W_;UaMXL+oFAAK(z%MD>j5=L4r{v;{zc)nm@Ff5a6zaDJI z-YiFI2!8>dOx-Z&M4(DUggeRTqC**CvL?&eQ_*iJhN_gLNTCS~$WSRF0!c8D0h0oU z0feq6;PI@jK}=ZpfG8d>F)@*}ta)Ns2`j{~LWIDK^-k(mZ>Bv;&ohBkZ{RG*6lAhl zH_T;x-s&sym`=Et;xT`dol!j|L3lFH29V$bb$`cMK&2$@RCOr|E=Y;QvHhkCd8vp( z>ROAYY?I!)E5Erc$AQ)4G|@VrXyk)2M~*MHmFCAO9^8*$Vf&+$v^}tNE3(({!<$r z(tlwYsssu+gP9NJ3POq+^yc55RT4lBDIh6~33xm|t?AV2fRgwFLsdyIq*UUX)>4@_ z)O64!BZieSG)qnzhorGeH&6XUC4iz#f4Y4{0T?NU3urY(eWlTm4B;S&q%i`bX5Y)*Y*!hL_jj|Vj018S#{!-tG zuOd)6<94iq}IS!B0&@gfskFqP+lT1`N;)=nM(S$%@BoBMO0sbm+M&dQ{DI4s+P;k1&IvDLuyP3 z6sQ;$;HZR11i65|s2f0ld;!Q$41Z3uX!jQ}gsohV$jz<}ij3qlVHV9b+kU=LeDdD` zeEURD6(q?JCf0(4eDS#hC-QFvffxcz4T%VqD^UfkAk^?^0z`@0 zbYct=8YOx-`E-y_%;XO#p(I3RB0Cviln>%B(;q{eSUt0SJR8+U2i(aPaeweEAZ0wG z&J%Tq%gjD09SH~{1wBU+v+K%sw5}A%5K=y}TaOTl`pRQY4*k=Dh}RYIL|RsHVcnY2g#X zi4zb3OH?u()&Y@U4KaWyw^N|8t#v!l&9-1aaB?lwuY~qM+Z1QGF+>hYt2ezr zmmmAVPjx)VLdB0WdHCrAj8FcLLyv z1_uy;ic(>Wra=$|OA(yFvH-JrAOe!ZIIt7LN(>f31T6L@6%^3!0)rJ|80)L)2p|fa zfFZHH&d}A&Vs!LE2jkyd>@~R2K9D2P(7^Se`taeihni@%XyNJ*Ctmx5G$bKtTe@c6 zc`d2z&nG}??SH9RbfA_5%>Rtq*F0Km!?+NmhM*8pfQxH-B$AMP1>>^Je z1HmDeD|$iO*r@a8MNm}KE+w&EksFedv+d=(A2>sDxqp(Zl`O}0aNQSyqvevrnISnt z&iojDyO0oJHKMBHWEQWMG@n+&(9dD-Ib)iv|PaAYr9GgZ{ibQD%i%aZ<0?itN%<#thi6R?;b6*SQQHB zr%y%6o4az+)}}8&@PqZe+U$F~rXV5&*?a3{e}nrB1vbfTucdd5IXm4AY&)Y~&c~2N*qK$~&)63NXZVN4 z_kX`V?fMF}%Yk3x7T<;Tt+4NkRbeAHu+N1#U$GrFl=os^K=A}C`XPC=sfQ8!>McMF zvl*^oUx?0^iYR6jXA1@~n|w@Yp%~38lEKQ5_hWaWk>rs!Mj>wZO*yR)ie-G5t?;fAaFKj*y22@?yhq?lpin&J>S3kEtKiBdEf zb_`!Ym0g$Xy2~QJ+Kr`Lxv<3t2SN(NoplIa_BILT?(VD$EryHlo%~Rc<9R0yE;{?KuM%-s=raN`xssS8;|J%j*THB4ESbt?Z@iW(P zgsUcFuC$4|U@3-xdFqm1bJta=Tv_K2g0T!{ctL~|sV^OOW7Vj>V%4D8IWVQybftmlratY05ewVVF@Ykxs9s$s9Ks-v5FQJM?}BTeel)~USq%VxBc_Q|DnX5Pn; zF26nPdYA*~=OJm4UlU(sxK4h)$jzWU0XA!oTA3hr~Yg@`qI1 z@A3x@{RgT97n62xehbfiFXy_|9o@q9+b`rM(&}r+mA;Zi!Nue)o!GVCF^kZVoEry< z;7SlfCosu}sPN(LQQ}FrOD;>6aas@#9MsvA&8Uv@5o}d8_~fk>m*>>@%H}1v?`-eAVYNNg^DLmZp9UB|(wv`1`nK zhqrMgCR}_@5<@3#)nYw{PU30?{lWA8AkEo`Q;`miQ}z5bNy>RqU;*wvaDDE@l2cvkH9=G< zS|x;V!w`*dGo>C(uc(OjL<_8h$Z<`+5A}aq-}u>xiti^$&PMZy-6I4BUttaQ#pl4m zbOp0p!LOKoW3`)oHi{B1#!}5N>=%(;bSxx<47a-dQh$J(Ohv|AWg~W$bc0&P8rN+= zw>0&oYx#eJ^t&VyKZzxgbP0CdQRDzrx+FSvtVfoEgKy=N$56-eBs#O~$4sz%OcHmp z3Wug`y7}W&Y6M=a2{h!rEao%TJbvww*JH1HowU;=~cqPuWj z5j7ihwi!!Qt1Unbwe&JZQ+a3j|A&m8f5$`?u5SMFC24dzFN?az{eIuUjWV$~3zwLCV6cmqmzN*TfBjcd z8<`7#e0Y|`wkNU@uALb--)vx49IqJwV}Eao6}<6wrY8W#)E8LkL`>!mMXI=r_|xpz+DgzdDwQ&f_!Vna4Mq(Q${z$=6_J} zU^2FzHq(a8Du@0Ikhx2udeQ0hmbm$%(*d17SSq?DChu|sPyA5--Bz)L(|a@4a1zEH z`&>$8NL0;>Cr_{DBbJ#0KK9t%5XGQNnz4}jP-_E8CHX^3Vaa>Z`Kxc|yndvIUpjVz zqnbVcj-+YMGMTf(WE~?0w_?N~W`D%sZWuB63XB-6XM_hdeCHtqTzH=(gZ^>tTrZs+1wjzXsPEGiv6_R+Z-nyoX&qMSBWrv7^!%zz`@BnsPlL+-O#et&2rf z?yQW!vLDWW?kCB!XCEMn&Jlji6eHZBN-~E8zs!VxJbRWTDY@_w&F*K7?C=PT*k4FJ zYMLiQ^3+Wrz=lypM$%02qkj|V-l^w(RFRb|LU2O&n{}S7)`_TyM2ez1?30iGW{Pcw zFZHmcRt0FuU8gWS=@5M2j0&q$Ihje|QtkQTrjX_CFowOsIItuo?<^P4CUV${!xfqq zr~L+5WBTc+>q@6UTDR4(4JD5rG9 z49{Rdfw?=CGdW>`S;=41s$k=6cbbjo1u3|=(x?l*W!qu{x!25%RGb$2NHHyo1xqb)CqD4+X!e*S*`$DaQN00960`F|}t02T%STUSvZ delta 61351 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�!D?1B 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 R{5Jpq|NqG-^$GwM1^{fAwKxC( diff --git a/deployment/charts/quanxiang/charts/serving/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/serving/templates/_helpers.tpl index a3df9b9..329f23e 100644 --- a/deployment/charts/quanxiang/charts/serving/templates/_helpers.tpl +++ b/deployment/charts/quanxiang/charts/serving/templates/_helpers.tpl @@ -62,5 +62,7 @@ Create the name of the service account to use {{- end }} {{- define "imagePullSecret" }} -{{- printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}}}" .Values.docker.registry (printf "%s:%s" .Values.docker.username .Values.docker.password | b64enc) | b64enc }} +{{- with .Values.docker }} +{{- printf "{\"auths\":{\"%s\":{\"username\":\"%s\",\"password\":\"%s\",\"auth\":\"%s\"}}}" .registry .username .password (printf "%s:%s" .username .password | b64enc) | b64enc }} +{{- end }} {{- end }} \ No newline at end of file diff --git a/deployment/charts/quanxiang/charts/serving/templates/secret.yaml b/deployment/charts/quanxiang/charts/serving/templates/secret.yaml index 60bb82b..6adf3d8 100644 --- a/deployment/charts/quanxiang/charts/serving/templates/secret.yaml +++ b/deployment/charts/quanxiang/charts/serving/templates/secret.yaml @@ -1,10 +1,10 @@ {{- if .Values.global.faas.enabled }} apiVersion: v1 kind: Secret -type: kubernetes.io/dockerconfigjson metadata: name: {{ .Values.docker.name }} namespace: {{ .Values.namespace }} +type: kubernetes.io/dockerconfigjson data: .dockerconfigjson: {{ template "imagePullSecret" . }} {{- end }} \ No newline at end of file diff --git a/deployment/charts/quanxiang/values.yaml b/deployment/charts/quanxiang/values.yaml index 865bb12..865fc30 100644 --- a/deployment/charts/quanxiang/values.yaml +++ b/deployment/charts/quanxiang/values.yaml @@ -17,12 +17,10 @@ global: faas: enabled: true # 是否安装faas。 loadBalancer: &lb # DONNOT CHAGE &lbIP, 不要修改 &lbIP - loadBalancerIP: '192.168.208.193' # 此处填写LB的可用地址,如果使用了MetalLB,在定义的IP pool里的可用地址。 + loadBalancerIP: '192.168.208.6' # 此处填写LB的可用地址,如果使用了MetalLB,在定义的IP pool里的可用地址。 ingress: &ingressClass ingressClass: nginx - - hostAliases: &hostAliases enabled: true # 没有可用的DNS服务做解析时,需要将此处设置为true,配置容器内hosts文件。 <<: *lb # DONNOT CHAGE THIS LINE, 不要修改此行 @@ -30,6 +28,22 @@ hostAliases: &hostAliases - 'qxp-static.fs.lijy.me' - 'default.fs.lijy.me' +docker: &docker + name: "faas-harbor" # docker registry的 secret名字。不要修改。 + registry: "qxcr.io" #docker registry配置地址 + nameSpace: "qxp" #镜像地址的中间部分,比如:[qxcr.xyz]/[quanxiang]/[faas:v1.1.2]中的quanxiang + username: "admin" #有push/pull这个registry空间的用户 + password: "ZHU99jie8" #用户的密码 + +git: &gitlab + name: rsa # git ssh 的secret的名字, 不要修改。 + host: "http://192.168.208.51:8080" # git server的访问地址,例如:http://git.quanxiang.dev 或者 http://192.168.0.3 + known_hosts_scan: "" # 使用 ssh-keyscan -p 22端口 gitlab域名或者ip |base64 -w 0 生成 + sshPrivatekey: "" # 使用 ssh-keygen -t rsa -f git_rsa -C "admin@quanxiang.dev" 生成ssh key, 将私钥使用base64编码, cat git_rsa|base64 -w 0 + gitSSHAddress: "192.168.208.51" # git server 的域名或者IP,例如:git.quanxiang.dev 或者 192.168.0.3 + gitSSHPort: 1022 # git server 对外暴露的ssh端口,例如:22 + token: "glpat-Txxxxxxx" # 将公钥写入gitlab并生成token放到这里 + mysql: enabled: true fullnameOverride: mysql @@ -101,15 +115,29 @@ mongodb: minio: enabled: true + env: fs.lijy.me # 设置域名,需要和低代码文件服务域名保持一致。 fullnameOverride: minio - rootUser: Minio - rootPassword: Minio123456 - replicas: 3 + accessKey: Minio + secretKey: Minio123456 + replicas: 1 + defaultBucket: + enabled: false persistence: size: 20Gi resources: requests: memory: 10Mi + ## Create multiple buckets after minio install + ## Enabling `defaultBucket` will take priority over this list + ## + buckets: + - name: qxp-static + policy: public + purge: false + - name: default + policy: none + purge: false + # 存储的配置,目前支持S3协议的存储,默认使用的Minio。 storage: &storage @@ -124,14 +152,14 @@ minio: ############## ### quanxiang configurations ############## -fluent-bit: - enabled: true - namespace: builder + +### API网关相关服务 +audit: image: - repository: fluent/fluent-bit - tag: 1.3.7 + repository: quanxiang/audit + tag: v2.0.0 elastic: - <<: *elastic # DONNOT CHAGE THIS LINE, 不要修改此行 + <<: *elastic # DONNOT CHAGE THIS LINE, 不要修改此行 polygate: jwtKey: "1232234yqwufdyuiasdfsdf" @@ -143,7 +171,9 @@ polygate: imagePullSecrets: "" image: repository: quanxiang/polygate - tag: v2.0.0 + tag: v2023.1.12 + kafka: + <<: *kafka # DONNOT CHAGE THIS LINE, 不要修改此行 ingress: enabled: true hosts: @@ -158,6 +188,40 @@ polygate: path: / svcPort: 80 +polyapi: + image: + repo: docker.io/quanxiang + name: polyapi + tag: v2.0.0 + <<: *ingressClass + mysql: + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 + db: polyapi + redis: + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 + hostAliases: + <<: *hostAliases # DONNOT CHAGE THIS LINE, 不要修改此行 + ingress: + enabled: true + hosts: + - host: polyapi.lijy.me # 修改域名。 + paths: + - fullName: polyapi + path: / + svcPort: 80 +kms: + image: + repository: docker.io/quanxiang/kms + tag: v2.0.0 + imagePullSecrets: "" + signKey: replace-this-place # 替换此项的值,尽量复杂。 + mysql: + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 + db: kms + redis: + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 + +## APP values appcenter: images: chaos: @@ -165,75 +229,107 @@ appcenter: tag: v2.0.0 appcenter: repository: quanxiang/appcenter - tag: v2.0.0 + tag: v2023.1.12 mysql: <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 db: app_center redis: <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 -audit: +### FaaS相关服务。 +faas: image: - repository: quanxiang/audit + repository: docker.io/quanxiang/faas tag: v2.0.0 - + imagePullSecrets: "" + goBuildImage: docker.io/quanxiang/builder-go:v1.16 + mysql: + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 + db: faas + redis: + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 + elastic: + <<: *elastic # DONNOT CHAGE THIS LINE, 不要修改此行 + kafka: + <<: *kafka # DONNOT CHAGE THIS LINE, 不要修改此行 + docker: + <<: *docker builder: namespace: builder gitInitImage: docker.io/quanxiang/grc.io.git-init:v0.29.0 swageImage: docker.io/quanxiang/swag:v1.1.2 docker: - name: faas-docker # 不要修改此项 DO NOT CHANGE THIS VALUE. - git: &gitlab - name: rsa # git ssh 的secret的名字, 不要修改。 - host: "http://192.168.208.51:8080" # git server的访问地址,例如:http://git.quanxiang.dev 或者 http://192.168.0.3 - known_hosts_scan: "WzE5Mi4xNjguMjA4LjUxXToxMDIyIHNzaC1lZDI1NTE5IEFBQUFDM056YUMxbFpESTFOVEU1QUFBQUlOaFNQQlFXYUZLaWYzVUp4aWNCdzRFRjhMS0VreE5jVWorU2RzN3VjZGlFClsxOTIuMTY4LjIwOC41MV06MTAyMiBzc2gtcnNhIEFBQUFCM056YUMxeWMyRUFBQUFEQVFBQkFBQUJnUURBakpBdmRMOEtabkxvbFpFcGlUbWV2S2ppZDZtME5VVktyN0lPT0hHc2d2bnBnVUVudXRwV2R2cG80OEY1cTZIN3lIRkVETUpVS0JqeS9jNFBOS1JhdExpL3NmNlF2WURjcm00TDFONEV3NFliamcyN2UvVnByWGp6eHhUeGM0TG1WNVNPTmpnbVdvQmJGc0xFanNFL2RtT1hiclhRWGREai9ndXlQbjE2dXNhazh1cEpGV21ZWllmOGp3MXg2WFFXelVXUUZBTERsNHdyMnB6YkR5RSsyVzlYeUloeU1PV2dDdGMycjZ4ZVVXTENaZXQrblQ4Wk9iRW5DakFZV3l3VnBnRE5aL28vR0FRKzdBelJEUmxLa1M1TU9pYWlMY2V0OWpta0M5THlueVdQV0hLQWVYMk8zaTNYWERoU2czMlRWeVJTa0V1c0oyajhTOGtJVHdTVVdYeDIvaG1DNEdjREVPSnlZamRYOU9oM3IzWStYVHpBQThNVE9CNnhVVWtObUtWenpXVWh6RGtmNDNqaFNOT094dG9rQWw1eEtpbWwwMGplaVdFRmw3RzVFd2xHWmRaWlk2amhIRzBQUGxSeTQyQld5SGlFQWd0N2ZXSU9LUFVHVVM0bU9pMnNnVDlmOE1BOWgxVVVHM0p0cG1nTzhnc2hCZXlhTUkweTN0cz0KWzE5Mi4xNjguMjA4LjUxXToxMDIyIGVjZHNhLXNoYTItbmlzdHAyNTYgQUFBQUUyVmpaSE5oTFhOb1lUSXRibWx6ZEhBeU5UWUFBQUFJYm1semRIQXlOVFlBQUFCQkJQejZiRXRBOUJ1ZElWR29EL2lYLzlOZWhCd1lGV1EvdHpUM1VkWlkyUDRvcDNBdHpkNnFiODl2Nmt0bzVpNC9GRkhob1JtbEgrWFExSktjRjNPRnBMWT0K" - sshPrivatekey: "LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUJGd0FBQUFkemMyZ3RjbgpOaEFBQUFBd0VBQVFBQUFRRUFzNVFvSk9jakhHdWc1eDhzZGoyemtCQlVQcC85NjUrWWlvcldkZ2ZPMVM4aXc0dGtyODZ1CkU5ZjFJQ3FKVnJKUkZDWDU4VDlGeU9yNEViRkZ5TG9UbmozUnZtZlRHVUZ5RlBkaHl0UURTVE93bVFSWWh5ckgvSjY0RjUKNkhGM2dTTjUrbkk3cTRrbVdUQ0tJK0ZROXBLaEorc3MxR0RpUUtEaE0yNlk1bDZyMU9lRXdYd0xOR0pyMHZpWWZzUFpUeApMeUZRTmRqSy9TU1RHbHc0RnNpNzlsVXRZdmtFWWRkbVdVeXI3SndTbFRWUngveG9tM3RIYUpUSUQ0dXFhUnpsZFovNjlaCkZidUR0QzZaV3BUNWQ1emhNU3I5b0lNb3QvcE9ZZCsvODZSYndSNFd2V3ZXcE9mTy9IN0k3YXFNaTF0TUJ0UEtFeGtOVXQKQy9obzI1SjZKd0FBQTlDZjVqNjBuK1krdEFBQUFBZHpjMmd0Y25OaEFBQUJBUUN6bENnazV5TWNhNkRuSHl4MlBiT1FFRgpRK24vM3JuNWlLaXRaMkI4N1ZMeUxEaTJTdnpxNFQxL1VnS29sV3NsRVVKZm54UDBYSTZ2Z1JzVVhJdWhPZVBkRytaOU1aClFYSVU5MkhLMUFOSk03Q1pCRmlIS3NmOG5yZ1hub2NYZUJJM242Y2p1cmlTWlpNSW9qNFZEMmtxRW42eXpVWU9KQW9PRXoKYnBqbVhxdlU1NFRCZkFzMFltdlMrSmgrdzlsUEV2SVZBMTJNcjlKSk1hWERnV3lMdjJWUzFpK1FSaDEyWlpUS3ZzbkJLVgpOVkhIL0dpYmUwZG9sTWdQaTZwcEhPVjFuL3Ixa1Z1NE8wTHBsYWxQbDNuT0V4S3YyZ2d5aTMrazVoMzcvenBGdkJIaGE5CmE5YWs1ODc4ZnNqdHFveUxXMHdHMDhvVEdRMVMwTCtHamJrbm9uQUFBQUF3RUFBUUFBQVFFQWtOZWpPWUNrdFR1cVlFQ28Kb0FaTVdwcVJHS0g3TUoxZGNBRmowWGVpd0Jod3RjQXN5aEN1SDV0RVAxbVB4TG0yNDhWdHY4UUZDWFZiK1FrKy9CUDUxdAp5TjNFSHA1cWorMXlKaFlqTjNJd2ZxSE1HQWxpVlBnTmFVTFpqVDVYNFhVMzRXVlo4NVYvdE5pTjB6cmREc1JkNzlDa0svCmlwQk8rK05MbXo0YnZpVHZ6Wk4razEvei9LQWlsOEJIeTdwNEx1ZzVrMUZTZjlYR3Q0U0xLVS9uQ1VEQ2xySTMzN052dVgKcXZXbDZwNDRHcFBPU3NlaFpkSW5BQ09KMU5YUnBRSW1IWjVJWklsdUdkTWs2Y2pDd1hsRkowemFPMHo5ZnRrTDZOR202VAo2b2tpTjZZMlpFS2w2cTN0N2VmazdBcDQzWVBmRDNvRWlIdWNtL0NvRTI0RGdRQUFBSUJIazVJeUlnTG1aWVFEeEI3TGgzCmJJTjQ3VkpmZEx0c042MldHUWZjSnNpTnJRMWxIVkhDSmdWb3ZWYldqM0FXNVhkN2RtVnNheGxDRElZTnhmcHBZYUk0QVgKUUxGNGlRVC9kWERpblBIUlFFQ2ZzZ0RqN1NlK01rV3ZuN3pEcUpySXlSYjdHZWZkQ3psWm56ajlqMkNodXQwZzg0T0hUNgp3K1pTZ2NoeFFld0FBQUFJRUE1M1MxdUpYTld0aHZpdFdHMGYzNkt0K1k2c1I4SmdBQ3dZeFdmSVBFdHBCU0ROYllnN1lUCndpU2NJWmRwaWNpK2dBU2c1eUw1NFdIR0tjZmZKN0hZSFI1L0dGR3JGQkE2Wm5ZckZ6eE96Mk5TZ2YzWDJFWVBpUFIwMngKcjFIWno5cUNYSmc0c2pyN1BEeFNQb0tvcDlaNXp1bTBrUXVzb2pOWWRKN3JoVGRMRUFBQUNCQU1hZkpia24yREFENmgwOApYbVpoVFA4dUUxUlIvQllFdElkNFl6VnFLak9UVi9BdHBXdWF1R09kaWNYcWJjK3JpTGNuTU90citqbWFWcEU0WkVoUk9BCnlhaUh3cnJTOTVkaG1DOUJqeTFURGJMVkJTYk14a215QlE5U2Zlclh2QUk5YzlHRFp2dk9vQUpuSzhKYndYS3hEV3pjbTQKdFFuQ0duUW8wRkhjNzNKWEFBQUFFMkZrYldsdVFIRjFZVzU0YVdGdVp5NWtaWFlCQWdNRUJRWUgKLS0tLS1FTkQgT1BFTlNTSCBQUklWQVRFIEtFWS0tLS0tCg==" - gitSSHAddress: "192.168.208.51" # git server 的域名或者IP,例如:git.quanxiang.dev 或者 192.168.0.3 - gitSSHPort: 1022 # git server 对外暴露的ssh端口,例如:22 - token: "glpat-TQE5zFwDhqp2UkGA65Uk" # 将公钥写入gitlab并生成token放到这里 + <<: *docker # 不要修改此项 DO NOT CHANGE THIS VALUE. + git: + <<: *gitlab +serving: + image: + repository: docker.io/quanxiang/serving + tag: v2.0.0 + namespace: serving + docker: + <<: *docker +implant: + image: + repository: docker.io/quanxiang/implant + tag: v2.0.0 + pullPolicy: IfNotPresent + imagePullSecrets: "" +fluent-bit: + enabled: true + namespace: builder + image: + repository: fluent/fluent-bit + tag: 1.3.7 + elastic: + <<: *elastic # DONNOT CHAGE THIS LINE, 不要修改此行 + +#### 定时器与流程服务。 dispatcher: image: repository: docker.io/quanxiang/dispatcher - tag: v2.0.0 + tag: v20230322 imagePullSecrets: "" mysql: <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 db: dispatcher +flow: + image: + repository: docker.io/quanxiang/flow + tag: v20230323 + imagePullSecrets: "" + mysql: + <<: *mysql + db: flow + redis: + <<: *redis +process: + image: + repository: docker.io/quanxiang/process + tag: v20230323 + imagePullSecrets: "" + mysql: + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 + db: process + redis: + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 +### 批处理调度器。 entrepot: image: repository: docker.io/quanxiang/entrepot - tag: v2.0.0 + tag: v2023.1.12 imagePullSecrets: "" mysql: <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 db: entrepot redis: <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 + hostAliases: + <<: *hostAliases # DONNOT CHAGE THIS LINE, 不要修改此行 -faas: - image: - repository: docker.io/quanxiang/faas - tag: v2.0.0 - imagePullSecrets: "" - goBuildImage: docker.io/quanxiang/builder-go:v1.16 - mysql: - <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 - db: faas - redis: - <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 - elastic: - <<: *elastic # DONNOT CHAGE THIS LINE, 不要修改此行 - kafka: - <<: *kafka # DONNOT CHAGE THIS LINE, 不要修改此行 - docker: - name: "faas-harbor" # docker registry的 secret名字。不要修改。 - registry: "qxcr.io" #docker registry配置地址 - nameSpace: "qxp" #镜像地址的中间部分,比如:[qxcr.xyz]/[quanxiang]/[faas:v1.1.2]中的quanxiang - username: "admin" #有push/pull这个registry空间的用户 - password: "ZHU99jie8" #用户的密码 - +## 文件服务。 fileserver: image: repository: docker.io/quanxiang/fileserver @@ -246,7 +342,7 @@ fileserver: redis: <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 s3: - buckets: + buckets: # 修改此处,需要同Minio定义的buckets或者使用的S3兼容的对象存储的buckets保持一致,readable为公开bucket,default为私有bucket readable: qxp-static private: default storage: @@ -259,17 +355,10 @@ fileserver: - fullName: minio path: / svcPort: 9000 -flow: - image: - repository: docker.io/quanxiang/flow - tag: v2.0.0 - imagePullSecrets: "" - mysql: - <<: *mysql - db: flow - redis: - <<: *redis + hostAliases: + <<: *hostAliases # DONNOT CHAGE THIS LINE, 不要修改此行 +### 表单服务 form: images: premit: @@ -289,8 +378,10 @@ form: <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 mongo: <<: *mongodb # DONNOT CHAGE THIS LINE, 不要修改此行 - kafka: *kafka # DONNOT CHAGE THIS LINE, 不要修改此行 + kafka: + <<: *kafka # DONNOT CHAGE THIS LINE, 不要修改此行 +### 账号及用户组织信息服务。 goalie: image: repository: docker.io/quanxiang/goalie @@ -301,26 +392,36 @@ goalie: db: goalie redis: <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 - -implant: - image: - repository: docker.io/quanxiang/implant - tag: v2.0.0 - pullPolicy: IfNotPresent +search: + image: + repository: docker.io/quanxiang/search + tag: v2023.1.12 imagePullSecrets: "" - -kms: + elastic: + <<: *elastic # DONNOT CHAGE THIS LINE, 不要修改此行 +organizations: image: - repository: docker.io/quanxiang/kms + repository: docker.io/quanxiang/organizations + tag: v2023.1.12 + mysql: + <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 + db: organizations + redis: + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 + elastic: + <<: *elastic # DONNOT CHAGE THIS LINE, 不要修改此行 +warden: + image: + repository: docker.io/quanxiang/warden tag: v2.0.0 imagePullSecrets: "" - signKey: replace-this-place # 替换此项的值,尽量复杂。 - mysql: - <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 - db: kms redis: - <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 + <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 + jwtKey: "" # jwt加密密钥,尽量复杂 + accessTokenExp: 2 # access token 失效时间 默认2小时。 + refreshTokenExp: 24 # refresh token 失效时间 默认24小时。 +### 消息服务,mail,站内信,websocket message: images: message: @@ -348,18 +449,8 @@ message: alias: quanxiang sender: mail@lijy.me -organizations: - image: - repository: docker.io/quanxiang/organizations - tag: v2.0.0 - mysql: - <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 - db: organizations - redis: - <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 - elastic: - <<: *elastic # DONNOT CHAGE THIS LINE, 不要修改此行 +### 前端相关服务 persona: image: repository: docker.io/quanxiang/persona @@ -367,47 +458,6 @@ persona: elastic: <<: *elastic # DONNOT CHAGE THIS LINE, 不要修改此行 -polyapi: - image: - repo: docker.io/quanxiang - name: polyapi - tag: v2.0.0 - <<: *ingressClass - mysql: - <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 - db: polyapi - redis: - <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 - hostAliases: - <<: *hostAliases # DONNOT CHAGE THIS LINE, 不要修改此行 - ingress: - enabled: true - hosts: - - host: polyapi.lijy.me # 修改域名。 - paths: - - fullName: polyapi - path: / - svcPort: 80 - -process: - image: - repository: docker.io/quanxiang/process - tag: v2.0.0 - imagePullSecrets: "" - mysql: - <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 - db: process - redis: - <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 - -search: - image: - repository: docker.io/quanxiang/search - tag: v2.0.0 - imagePullSecrets: "" - elastic: - <<: *elastic # DONNOT CHAGE THIS LINE, 不要修改此行 - qxp-web-home: image: repository: docker.io/quanxiang/qxp-web-home @@ -416,13 +466,11 @@ qxp-web-home: redis: <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 <<: *ingressClass - qxp-web-nginx: image: repository: docker.io/quanxiang/qxp-web-nginx tag: v2.0.0 imagePullSecrets: "" - qxp-web-portal: image: repository: docker.io/quanxiang/qxp-web-portal @@ -431,24 +479,11 @@ qxp-web-portal: redis: <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 <<: *ingressClass - qxp-web-vendors: image: repository: docker.io/quanxiang/qxp-web-vendors - tag: v2.0.0 + tag: v20230322 <<: *ingressClass - -warden: - image: - repository: docker.io/quanxiang/warden - tag: v2.0.0 - imagePullSecrets: "" - redis: - <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 - jwtKey: "" # jwt加密密钥,尽量复杂 - accessTokenExp: 2 # access token 失效时间 默认2小时。 - refreshTokenExp: 24 # refresh token 失效时间 默认24小时。 - web-process: image: repository: docker.io/quanxiang/web-processors @@ -457,14 +492,17 @@ web-process: hostAliases: <<: *hostAliases +## 系统初始化服务。 init-job: images: initdb: repository: qxcr.io/lowcode/initdb - tag: v2.0.0 + tag: v0.2 mysql: <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 git: <<: *gitlab docker: - <<: *docker \ No newline at end of file + <<: *docker + elastic: + <<: *elastic # DONNOT CHAGE THIS LINE, 不要修改此行 \ No newline at end of file diff --git a/deployment/scripts/init-artery-engine-persona.js b/deployment/scripts/init-artery-engine-persona.js new file mode 100644 index 0000000..72a3d28 --- /dev/null +++ b/deployment/scripts/init-artery-engine-persona.js @@ -0,0 +1,112 @@ +const allPackages = [ + { + name: 'all', + label: '所有组件', + version: '1.0.0', + }, + { + name: 'system-components', + label: '系统组件', + version: '1.0.0', + }, + { + name: '@one-for-all/icon', + label: '图标库', + version: '0.6.2', + categories: [ + 'action', + 'alert', + 'av', + 'background', + 'communication', + 'content', + 'device', + 'editor', + 'file', + 'hardware', + 'home', + 'image', + 'maps', + 'mobile', + 'navigation', + 'notification', + 'places', + 'qxp_ui', + 'social', + 'toggle', + ], + }, + { + name: '@one-for-all/headless-ui', + label: 'headless-ui', + version: '0.8.3', + categories: [ + '基础组件', + '表单组件', + '高级组件', + ], + }, +]; + +const headlessUIPropsSpecURL = 'https://ofapkg.pek3b.qingstor.com/@one-for-all/headless-ui@latest/props-spec.json'; +const headlessUIManifestURL = 'https://ofapkg.pek3b.qingstor.com/@one-for-all/headless-ui@latest/manifest.json'; +const iconManifestURL = 'https://ofapkg.pek3b.qingstor.com/artery-engine-person-initialize-json/one-for-all-icon-manifest.json'; +const iconPropsPSpecURL = 'https://ofapkg.pek3b.qingstor.com/artery-engine-person-initialize-json/one-for-all-icon-props-spec.json'; +const systemComponentManifestURL = 'https://ofapkg.pek3b.qingstor.com/artery-engine-person-initialize-json/system-component-manifest.json'; +const systemComponentPropsSpecURL = 'https://ofapkg.pek3b.qingstor.com/artery-engine-person-initialize-json/system-component-props-spec.json'; + +Promise.all([ + fetch(headlessUIPropsSpecURL).then((res) => res.text()), + fetch(headlessUIManifestURL).then((res) => res.text()), + fetch(iconManifestURL).then((res) => res.text()), + fetch(iconPropsPSpecURL).then((res) => res.text()), + fetch(systemComponentManifestURL).then((res) => res.text()), + fetch(systemComponentPropsSpecURL).then((res) => res.text()), +]).then(([ + headlessUIPropsSpec, + headlessUIManifest, + iconManifest, + iconPropsPSpec, + systemComponentManifest, + systemComponentPropsSpec, +]) => { + const keys = [ + { + key: 'PACKAGE_PROPS_SPEC:@one-for-all/headless-ui', + version: '0.8.3', + value: headlessUIPropsSpec, + }, + { + key: 'PACKAGE_MANIFEST:@one-for-all/headless-ui', + version: '0.8.3', + value: headlessUIManifest, + }, + { + key: 'PACKAGE_MANIFEST:@one-for-all/icon', + version: '0.6.2', + value: iconManifest, + }, + { + key: 'PACKAGE_PROPS_SPEC:@one-for-all/icon', + version: '0.6.2', + value: iconPropsPSpec, + }, + { + key: 'PACKAGE_MANIFEST:system-components', + version: '1.0.0', + value: systemComponentManifest, + }, + { + key: 'PACKAGE_PROPS_SPEC:system-components', + version: '1.0.0', + value: systemComponentPropsSpec, + }, + { + key: 'PACKAGES', + version: '1.0.0', + value: JSON.stringify(allPackages), + }, + ]; + + return window.__httpClient('/api/v1/persona/batchSetValue', { keys }); +}).then(() => console.log('artery-engine persona initialized')); diff --git a/deployment/scripts/init_nav.js b/deployment/scripts/init_nav.js new file mode 100644 index 0000000..9cf3e0f --- /dev/null +++ b/deployment/scripts/init_nav.js @@ -0,0 +1,78 @@ +const NAV_LIST = [ + { + "id": "app_views", + "title": "应用视图", + "icon": "view", + "children": [ + { + "id": "views", + "title": "页面管理", + "icon": "note_detail_duotone" + }, + { + "id": "view_layout", + "title": "母版管理", + "icon": "row_top_duotone" + }, + { + "id": "app_nav", + "title": "应用导航", + "icon": "tab_duotone" + } + ] + }, + { + "id": "modal_api", + "title": "数据管理", + "icon": "gateway", + "children": [ + { + "id": "data_models", + "title": "数据模型管理", + "icon": "database" + }, + { + "id": "api_proxy", + "title": "第三方 API 代理", + "icon": "api_outside" + }, + { + "id": "orchestration_api", + "title": "API 编排管理", + "icon": "api_arrange" + }, + { + "id": "faas", + "title": "FaaS 函数管理", + "icon": "faas_control" + }, + { + "id": "key_api", + "title": "API 密钥管理", + "icon": "api_key" + }, + { + "id": "file_api", + "title": "API 文档", + "icon": "api_inner" + } + ] + }, + { + "id": "setting_flow", + "title": "工作流", + "icon": "data_model" + }, + { + "id": "app_control", + "title": "访问控制", + "icon": "role" + }, + { + "id": "base_info", + "title": "应用设置", + "icon": "app_setting" + } +] + +__httpClient('/api/v1/persona/batchSetValue', { keys: [{ key: 'PORTAL_APPLICATION_SIDE_NAV', version: '0.1.0', value: JSON.stringify(NAV_LIST) }] }) \ No newline at end of file From 9f53d61ed7567be6a04d5e50c1e8170d7ef0e818 Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 30 Mar 2023 10:44:48 +0800 Subject: [PATCH 4/4] feat: add init nav, artery and elastic index --- deployment/charts/quanxiang/values.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/deployment/charts/quanxiang/values.yaml b/deployment/charts/quanxiang/values.yaml index 865fc30..d806d30 100644 --- a/deployment/charts/quanxiang/values.yaml +++ b/deployment/charts/quanxiang/values.yaml @@ -461,7 +461,7 @@ persona: qxp-web-home: image: repository: docker.io/quanxiang/qxp-web-home - tag: v2.0.0 + tag: v20230328 imagePullSecrets: "" redis: <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 @@ -469,12 +469,12 @@ qxp-web-home: qxp-web-nginx: image: repository: docker.io/quanxiang/qxp-web-nginx - tag: v2.0.0 + tag: v20230328 imagePullSecrets: "" qxp-web-portal: image: repository: docker.io/quanxiang/qxp-web-portal - tag: v2.0.0 + tag: v20230328 imagePullSecrets: "" redis: <<: *redis # DONNOT CHAGE THIS LINE, 不要修改此行 @@ -496,8 +496,8 @@ web-process: init-job: images: initdb: - repository: qxcr.io/lowcode/initdb - tag: v0.2 + repository: docker.io/quanxiang/initdb + tag: v20230330 mysql: <<: *mysql # DONNOT CHAGE THIS LINE, 不要修改此行 git:

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 diff --git a/deployment/charts/quanxiang/charts/minio-5.0.33.tgz b/deployment/charts/quanxiang/charts/minio-5.0.33.tgz index 6357ac5601c5d69680d6c024a89ba80893b3a1b9..37320ccc9660c337af874f6a1470898293d4d37a 100644 GIT binary patch delta 18886 zcmV)+K#0H7mI2b10g$tQ`#Zhez208$@fW=v^~V>``xwAfpHxVae9`;hzN*OmNgfij zpJ*Z&kNR-6sb4lmwx9B@A2+0#Np^giD^c(f1Tf7+TIT2Akx9W^I`VvfKI`h~rAuCAgnj7syuCf=Qx82p8o()9z1~agkQ0M0s+O>z#@o4;#1&b&Ehywha`^sLkP);hQfL90O!DqE1D!M zpnd3c9H-utQiHX!-7hMsr6g9qS;j7BoY&`+qskL2x-QvZ_5El;64^G_Eb>^Eck(B1v|Vt3Eo-*fjKEyVW2 zQ2XtTLGAm&i!;?!oN%8CQAJHqKcN!q#R;ELIi;z90Zp!dm`|VcNFk-sozigjLpq|q z48MQVi1|odvf2K_t}5wX>Z0y%Z!$vcc{^Tj8OEBG1x>DKf(*9}%%dI%Nuq#+Jfgr8 z2$+xw8>Ny43N|<{eyhcpaY*R6SPTR13lCdXYohwqwOVlTi~A;J{-qL$(w(F%K#o=b z^sT-T#KRzeU}{+=A&_K}&S)fsqG(J6{;N?Kv4|vdhrX2wIZP&^53hd3>OaN-5?&@m z(up3jV;YBijx9OG-@2rtvYf}X4=;HbvS^}TI{-8C_Q!}^5f+kBNc+&!?*?fyp?%ot z_5OEjhXY9@9jD=dO5s>PiY`<9YhWr>J4cbn1BerU#uFyzN=!)>O_VGv)4q^hIqiKO z`81aJ$Cyph1ht%Q%mX)T&y5pGXQ*j))j(wLk3u5E87d)0KH5`+_=?3Z>3rMpHU6m? zLiYt@7E*|boNmJv57QZi8BZgLuhfiEO-AW#L=z>VBOXuzn>-5Vdg3VB>GmuJLO$I> z)<6J%exP%loEir8iwT&}h$>nJN@hn8aj9tbF`1XXWkQX~0Kq_lkqkckmBWX>e40pc zPUN%?oi3HW(ctiPx8rE~sqZttTw>;TI}TDYul+XWiPYnhEodl~63!(AETO)V7;rsh z{uFWnoK1T%u)TW+-cMSw%i)6e z?@cQK9kYlA*u*Rq5=KhGi*)1`knu6Lh+H9J>a#JUfl?6Kn$`=$OU|X?OgPKAC`i~9 z6+omU{!~j}f~@7}FXuElLqW4ss-|}pK93|}5lxEKJ)yWY5PjG$RiJNU5(S!zR875q zmgzCKpA9>$@LIo*wf;3Q@IKhOZY7>_V7ERzhdn4f|Ejx}v z!e(We*DUfVY_f8HrL7hI91?nb4pCBt>@wOV@cx z-=r*|!bZm{H;(1(d2#;JQ9dy=v4f)L5gqe{X2SEDg`p}o;%O8pu#L5D?C;(ql68tM+lD>$1#h8Nqj+)F<<`koxj!@__f#aZ;ZonOtc&xi!Co3D}zI>#GJg1xzJ1G^L!;_KJFvc>Vzax>PNz7z*8x*1vT3a zZa(8ActS!F`Dy{xwNY<>SNy8$t6|3mlmKT@x&D#<q$Y=rj~t<`BkX8YCSyXD60JovOfHelH6Pg^S}3cO52T0u|DkW?EL*}!z9m` zz(GDe2NDE{BAr@&Ep_9(*y?0Dhry8v$TjLrf-cr(n~-`y-%6T)L?m=sEV4n*-kqN7 z%>aO!({AxT-cbmUDB=<|V$p|p?;QYDu-Kfbj)k8PMW!#60ROVFNR0di@TFN-i?7`o zl?n4jOFbkfz?X`|Um|xN88w~4X*5yfgb`8P$TbfI+{aCjwpFUBznb=+QOk{}yynRz zizZ#BJJ4K_Z*KK}lCG)t09?>k$PRvY)ppWo03F9M4K(U9+Js{fRk4qo@Q`|CII~6| z4v8G|WY#_|jTJp#3%qE;qPL9&Whh+YBNl21I}2MQVaTstoL105WEPj7gnUFoS14$G zm&I;WNLxf(f#qeT%WVkirwMgO#J{9bAS&=Js%fgYal$2k_j%Zd&UY6V=Yv)1UQd~% zArsQoCNVc5k=n!dJp8YVW&>pCt^+XTLgEOk+2c>uriZ>IvpA&2yak}t*?f+Rl*q&la@HIhHz}J3sB2d0)-_#FARLMx1x?U| z(aYXERS@K_#--nmG0G5Qmcj8TrmGY4;IJ}#osu1YM^!Ke-k1l^3OV86a&ko@CG`{` zl!n6aSDf&X*>ehS6|;vV;M)!A%PakBG-NPh~OGjd5?4YB(hA8k46g+}*#KI&H# zk=ym5ZM$xv_!<3a%h6v7^|-N1u{R--UXyvFmStO~Ak(W)q9EohlBGSLwmjm7r-MZc zb0ogp+1=ZJ_(<=NeiWIJkf>P;e-Tk^GhIv)5{5L?3?BJZRH#ga$NHD+~N4c%&`%e4Ovli0|W;|B@Z#2`Gct#363NVPWb8jj+G=fV;Xa)IcQbBbSBDc53L}WW~UL0^~RdQ3{Sri^Kp?jOs&;vYGq=939b+52&)4cl7 zc_=z&c@HTON@*I?1XmTM{UmfsBf+jHF0;$IS)=2Yj{LMTW@G{5^q_if> zBuCcIR%|_>3IP|ASvLy*# z$SF;(nV{R5YfV;!q>{V&sj8Q0wvJ=WTY4w|T>k){=rh+5&6dZ10OnLKJ&s~Rq*Qbt z@Be+T&}NKZgx2h9!w+hj8-?sy&E!O8RK&!meVFN1^qGVD#v)0RE5+J-Jz?HyOW%dw z1gY(=&<5j+qvM>%mm*OUdqRpXm42Xvp8B_MtzVhpBqnltp3pISYgSgDCp3ugh`9V7 zeP)hmB5N|2542wgoWD4JeRlZ# zXb=P^lV;#KcgZ$>3i zyBbe*^1icwrQq82AcI0dr_|+Zk_51kfr*DjD*@&>FDVIN#uEx;#8at9)U>DutT^3R zY9cZ~W&ggmf$KWX&pb7Y(sg-A%z+e-vTpL>=_^D$_!im68YUrWj8-+DM-laFI;37{ zXTA~4*=QacV~3@3g|b=M<3CaNjza-~3jN6mLBE4zqlGv4;R%FPFgnM(65 zbGUl{9tL|?`wEslge4TKcJDZcA*z^?hGtKs#!2aCI5S5HzZPnMY+Y?|`~&LudLT3P zh$gLc^ogVso-iu9JC7YDi)a)m7F;Hl?1SD97e^$@j~}h$QV*V1j(!^o!D!xh?D;RQ z{FSGFKZ)amrQ_i^XIz@iB_27W$x(rzHmPX!BjEEi4l|eSR8oX9x6WMqXSTg? zPtU*kH=A!|+!yf8zsXEgOD`Ma{%SMBtF%eYj<&X7Q*AAp%ak^)TdG~f)O{GR$fs~- zmqq`R%#x2sYPh6o6TaF=ELR2$lN{(n+kC5kGzw{jU(qh1%_*6RVB`L&m9u+zs`~%y zDGg(qyw+RK*V+XCf%}0a`v1e-y~h>(|MC9L!_WHveLN5TqdQ_zS4K2k6s_WIQ#bW>FeXumj@kx zOGs8qcAV!&2c2#z5(I3fR#RQX4Ojvj?@BGb@96m&3aWc4Rqd1n*@JB6UvTa1t8J46 z{3-P>T@g|myZASRoX1K&ToWcOZ}*BnTJ9lLZg+DF-Z=n+qwh}C?qJ6OIJ~$xd47H| zIOxGY;MwW((~E=Mzayy+aaG;x0g-Bd5=w#gm3$-=nH5>DsS^5MN=T?#Ixp!Q-4hRw zj!p)HgN;p}NHFK;-TVr`7W@MSCr2+&E-EGRn*m$!57Xs;>Mk#)G$RxqpyhWth}sV* zaJBQc0!;xx{V9jek*N_)s(L^lHZ&>v-R_1qw4R(DpT9UgyXc$W=PzDfbPx`I9Ng#6 z56_MdI%=rj*Ov3yTtl-`qp+dL0~?wMx|5Bf7yLcAIK23AaIo=T_$!Sh3*i-P=+|%n zJ^0lD2sj#}@}V5kw{Zd+*>Cty*coC2h9tjqzSVOi8`*wQ_?M0;$;PUuybX6EVFURC ze*K3U=E%`rI5-P;OrN4|=Fz$2QogyF)3 zsvko-#A8QavMYVWDbpl^o}=fMnmGD|_Cz0iZ*G`-V$K6N!fC~{&9rnrz73P-dVt%bl2T!Pu=R=Zq7NIo zSgr{1B=4x?tz&n8*}zOCiDB<0%Z)_ZM%Z4!5N%-*6ftOQ(YRW)$vlyofzHhgdkY=6XiSL+S6isMUpYtBAO+(z4CnAB zC855yO5zyd_MCrF-8z<+st<*O(wBXb3JQYHO8$cSY)ZSHs7(;M%IZxJuAQ4B?ayG& zvDD%tV(M>ydCut=%n6Tf#CWF&O*9j4LzdhSP=hIAWV8~tuz0zJy*#63HI7DJrnSII z1Xqhh_G1Hq?;or_rWTwz9ds+@qpuv+(%ZEGj1v~gF?9a7aR0aHR9e&huES+*f0ww= z8dfz`OvE2Gq&T#OPjo4?Wws74mg%%2W7AsyZNfHx!3{cK5uZZmKReKQ-MPhFdZ{-? z=ra??36B$ob0v=zg$kgt@ahGzBrzkl?Yq5g_~(xI z*zGBNNlZp8WRg+gsi|pN@t!i7!BnCZbm&`2BY|#9S34sr$xek)>iz!TAJAQKeapN2 z8jnJMuXYx5(K@sa@^Bcfgtm&TM&*C*cz?ewwj_=-vhFULe|gEfBSm(>N6>a!*kxLX zQO5f4{L~Z@-giW_A^7RB&u)&jVV>WXTa^WN_CMMLyQ3L$OeIZb3dgGNoL-nq(*suJ zkdm+8S=&NdF6NnVK~;5TlSO`*22H0?TWw8$nFZ)p!rCTo21CdE(OKBxa%!I^Jf?}Z z7tM$S9%oU0S_1w&w*&pOP&<$RQy@{^J>~_>cj!O|-oIB{L|A9$#0WhcbN`Yifbp5& zC7m!KlR4-Mw1B7Zt@EdH+cpEZ`<3$@4QH_H?d)XN-1Wg~aplomxkt}!^b^kc8us%mlgs^;@(=^s3p|b+E0rpM z-V-$zG&`ZZq}fpSYo1kEfhkRxB$G-B6U zo)AGX;7X_6MWV9>9^3$n0wt37{}lGi>ioBM5qBm4mc)O3xc8_U|MlVi?q~mxdwJ@P zmKfi(Q$&00m?MIXBDfp$50sw0xluO$t4~|j+dMQJI(*rZreT`5Y+rHOYpGO(g#2rY zB@t7MSN= zwjfkHu0{ba@NWtbY)y`Trkb7VRifV6CE^XE#QDD2o+o6y08J&Yz zkC|kHRg0Ts7`%vsjc^w?=@!LDq~bAI{H3+=@WpJNue#-K)FIy zNw#Q^#mcVLDFRU2N^)b(PD6LKQCj%A>=WFuJmzPi(ht0UB6>*Mdws36k)ryhY$|Bd zPF0<|q6jl4su(7e1TUg+o=3k~70VX?>Lx(dTs2YmOd5cd*ub9R6$t8Z;Yn@doLK`< z?G;|_swUsc6;`2{wFfx2V|r%~jjsBQ9q3C=$1k2Ao}N`rTe!Dw{V2B-;rh1aBB z|8VkiQ(NDECVbYfe6S)FzNF*&SIfL%k-D6X#hmaj_-07F)JD=Y@Y!=o=lvon&H^In zJ7RxfBIK9;7R`obihDt|r!QVSeRlHt@cjJQ>CxfE>5H@1M=wu~PtGn*51$R1nX)E! zx)Wc#zNB;SH^HOMEyN6p#XM}&Vm3dyI6BTR3bsIh`0gG2##scN?M_=CmWkt*@LJ-1 zIlxEHPEXD*ULT#jyjYc}s*~5clh;aGdNG~dnz$>iInD64O{P^~My~h}xQp0bD*%0d zc=6rq^Oq;zp8of8ak{wmbx2!{CbkNBU%WgyJ{us!tAV<-m(?Jyn|Rz+E7%b-8u2^) z*T7nTgkGN>|3yVGxfXePwA0{&2EmRl(n?darv3HT_iLfs&8fR8ZChSzue1%!owspC zLg*jZ>Qo-Qw1xI+$9Y*F8heUjtBaSC(%V|t`{GgB=2I%GqhyjrXdjO$C83;l!|ZNs zxwF;O;Vkh?T^(*!i0vw??V;8KNMF0`17_KOSQR9@(rQ38hWWRcyEHgnL+NURmFxhm zO_j=38>yxRXlgfkso2nKqH&xHHP&_T{es^rs!k10+DGTm@ zTR`q%LM`LnGO0g|c`I$*mU}DBd;t4aTKXXVt+cg_f%7yN^@HL3V{rn!vzr|eVyLTs z+%j%u!6`Z@<;JnwZ$D8+rYs-e)}7t0`i~mH$#U*k2mM(Vp4Gu9wPqAfm=x zX(G=N+qUeLGRH1$Ezd05+MJbd_70#sIuzXo2#Y~__c^FU(^K{T&h8K1-R+O1_dj-b z9`4rTKYaH8zL%#Wv$Em04LqvIhLU|}=Ei^fqEM7K?ltE;k@n8H6ht*IY&{D+PCLX^50v8!P^t zD>bg&7h4!ihNfMUa=m^LuvSv74OY_2QXPC>US;u)V9mVJ;ObajRg2$HbsR3$P12Aq zfxHBi4!m2e#EPj)3$trhGR2I4_JpV`cqVsJb?<8?)>#WbHx$*!jjE_US4)Ia<5s-E zAmpo%wV7m}TGD-fnx5+VUk>VVH(J1w^?zq?r+WYM(a!$o{2%x7RQ>RpB6}B0Xem(l zvgNov@(T);zw{lhm_ZU7cy=Ti^j2R!xpFQjX7 zPP;n7ft82(cA{X({NH~HyuVkT|GPUok9xBWB5whIKK`u#-^){Bdo#>lImNp@6V^Qq zzRfPdKD=^Mj1Xn>qMmi@Zw?l;^rzk>TvIlg%1$3T?!(U7y9lQ#7O5uHc}}V7&Y`?j z_-Olsg(J3fEI#6ZBuOSzg6sY!cm%E+DWxss z3Ak_I8|WJ9c4t1`3AL$Qy$t+fC+E?#RKDw`Ig(oUs}%Ui;KvNkDlC9mJ@wxp5nx1^E&zbbNLL56Az zxc2Z7?JNxyjk#Xpb{_7<*kQa4U&4rzgeDjKl16x%SPUvpWt_^|)cNhr;z^@czaMl? z_V3>;nLiC>*PBWW4ScLw_1hb8DY!nkzk!>8XA|z9wTWZTC8^5%!5Jd!*<{l=L<&R%SG)X9CDe!fM4c!B_F=ipHL1ERdsAyS<8BHb>MqEyzBGwfRzNs*pVFGZY znrbIvf@(BkUctH|9l_<;8Qjz?cWN$w`S9htTuX&_Q64a{q?r{fOJ^Hd6anaimsR!h zm)n_=3-3_7EsE&(9*N`aLTRmiHecRv>mhiV4T0#xt9SNJ%5taK2ECi|)IZxW3b}vz zLe)N2YCo2iNlLfTu$AyIq)GNBWq}Pu%7Se(2g|s<|MmU*FH1{v_7#cyx4*T244z>M z!#B7rGry+!S}V8fD*5j!4m&`Rbx@XI;JQIFcat>AN7jN$_tOFsCckbf*@Dy!a)`j3 z(^emR^c(eMRWbSFiPJ@qB{Km_;y9fDrR1x@tn#*srgxI@8soe3cv{!~m++9T zYXDs4|GEG0an=5}|LAl6&wF`)Rx)JV<`#&(S|uamdnA=pp0M9>BVJ?xGq%8&Jf#1g z#=!g{ff7^GKU(sY_eJXaQnPQgz)M)2FVpO)whqAFrqusG+f}w1<@O(aN@5R;#7t&`noIg(Dr9a4X8~HzCQJ}_uV%23}nf%}F zRptMFZ|8IVr+az+Nb>)Q=Bt0xWq^m&1X{`@-~z%q0M@#>Hkm|CNa zQqcdgq+V_QU-@?$`{9d!72-eidbRiuy`9hTAMWLOw`%^s^`p$U1{kWP1I*>ac~dZ> zzw%Ad2D&z+!f5yuU#)nNDZXk;g%@8nDP!6_2~VP*^MK~pN?RgF6(!3ao0W}uLf@p+ z3f&+iPspS_AeCUh)4B_2&7;Szp-I_d6K+}(7! zaFJ{dMZaqJ`En5U@*R|hIt^4<3A9Rp_Iil&mYx@m*J?^cW0Hxcq!10s0*YGeA>NiN zqAjn(qOR9N{!!Flm``)Wi}yJvUR%dZA~FNy5Tl8#Y+n6iBw# zhIZdz)qLCU+VlUfD5Dlio=+{tZ~e5a|7)G^Eqj)Ko&W9a>{sJI?tYH{ct6j|=YO|8 z&s#qV!!3OX{=Ad$6Fx2T-+0g6%lzNne^i_Qdpn=w|J}>8_Wgfb4mA2@cB|6CG;+(` z#A*OW*1e#*1X-(YNmKZP?`0Zv)D|R35HPh#A>pDs@T*oXZ*(eJZ59n6&zHKoE?rHA zRnw(^E2*#Qy0o34tMK*c8pKSg)kwx7Ns}u()NS@=6|Sn+t^vCm7{X6TOfPf>tfF%1 z^(p|hv{Qr1x>P!-M1)#3j9!D0EYFH2vR<6!zo@yf zw*E^Z={OC=9mM_3p2h3`Ztqd`{?E?CM?0T?t zRm)To8B)1<05Alp%;4XT=d4Q#~drqfnIeOt0|yj74`apm8eX4Yv~3OW_t ztkbNVb&6yF=_q7kddB5TN`m=e5F}IxD)cq%vi0?hNA%BPgZvnVG}m>P<(06PsFqYu z15;%1S9MUxSW9~~4`f0loy;}3HEXwjMU5Y^yjQN4nZ1MOBq9?!qfs7Qs&h^f5{5MF zIQ1MuE6vkP?qiKv8rsW118Ylu9jS(o~kBAsRK zUnO;UGfvd%yWw3JjJzjAP+X!qC4aHb7FzPelSsIz+9=xXN);|Y`V+&k2kos~}&7tV&74Y^Lt=I?F- z-Zpq23+kr`29G3tTaW*~FduEDa=~9o8Xbxs1x+ezOu4VTRB4W=m*zU$vbtEzt~_3$ z=D4UR28$Re+QxOv_y-OOqI^Kv0LPlA`T)fEK$w zyQ>9*obUdY(9Bx)EN_nDYb^?AInevz(b36Z@cM_7pDV3mbj)vmOWESGC--DxoA` zAI|QonfYgazjJ;s56_1&e5I}1a(tzk4`BI9OCQAZmA00DG5u{rW!6H-uNeWqVk&}q zYTC6!@;8EYyIA=RjC!Xr^BX6^k`!O5pmqez71B=qDU)lhhoarhePq^Z$f~uVwS-*} zNq=Zk%S>~+gjd&!KTh7S1$X94gLGAdk;sh8NIz4*!IofiwNYgQCN58dHakLo##TK> zfVx4!v{V>>Of5@tIqCwug34)bq3~J;mCR^TJ)O`;`En*qr{+&p5|G^rx&WE9w*(Bl#z4IPci2t=yz5l=au($u&|K~oQ2XIcL zq)8+|a?mUQ*Haq7C}m;5q6x&rza$eXJm&#iU@n1wG)4;+h$#(2n1pouF0$n{h(N>@5wnGV&i=9=wRcIq(Q;Dv*@s3n7cB=Xl41*8|BD z>O6oWKAZ6femWXJz!Kqj6DGU(e+|CljebwM`2Xz1bkbG-%YKThs9Q8NBK~C>V_E~@ zeC3IM>)83q8<9)rD^Jd1=d1s59>7l|VLTOZdVC@r&m<#tJQh&W)#VcY+n>=fP|yFD zCx^$+PrO<1QTkXo|95)3JA0M<-#a^x_CEXn-OKZwMW-*E1NAu0g9mW-;^Oq^q^~DB z`mMl}2$=CJ8vKXz|NX!Jk8_+-B`V~U!mEIP#tHTHgeFk{d?dI|IstJ=qF*<0|KIO+ zCrnP$5nc~aOHCJB77v6ZG8HZ#yK;)L`P8)90zSs(zoX$y!yv#qIhAG5MwCVxJ_Qzm zh+bQzJxryd7v?;X2_g+gx@9Jc+OPB%>{x$pL_tp)4cV6NLBqoYOu3LW03so)sA^?@ z`S^65|9W$v_aKg=dn|gHvB+b5OSMGcJ2siZIZehqnUTn+@B+iO!a%DJng2)tX%x@| z4rAg^DLi97jRb|OU9acCDMEF4ehNOH#YD1ENVUj4oRQyo1cN>BL!JhiQj$3rc<`gh zNF}*m4q&PviYRN?ez1Mt`GXE0O<++oT1$4`U(+H}K zZo{0X;FAbq&O?}`p=5DLLF@UjNv~)G3R*VCge)?{QEUN=kn04CCLsl#I-*2>N}70% z^R1$bT3Q1t2~*pXfcxo;M%o1hVjM`gVuDF{HKj=_qFau08p(tQsgDV6UF&fiYub)D zmqI2a7G@9w8i#z2ws$pM;nff6h$a!0)Npyf+r7+RAs3ocXGj%#ddjQ0QNU*SdMi^B zV1_Pa3gz>JVkR}gBo!qvUB_{M|5wpD?0EbCsaf&~l|=EXfNU417%IE@UBo2BQS%%Z z07~sVY;8w!NYcnqf<;Y?^`OQ+Tb|?ouk)WEPPiHw9?>LYP1S~?2hO~3uE+*_hD)MspyLM(j<0syjv=GL$iGdU{PDspK;vnU5I-i4bfOiK231K@ViC30&d< zM8JcejkqD9;2@|}@+W~9Q*J2&VFROi`{=ta7Mac6tj{_>D0=EpLnwBQMd^~xh2uP# z=VMM(ziyT@F)&+etRnI%aLvL{jbbWj;K2n4enpdn1+>IJs_|`qh}B+My>4tu01-fv z2}(cQb=a7B3s6>s%A+zJ%;xz)>~?;1dN7;kCzJ4tqxafPgh5AGH7a_Bl$aW>7{T#& zoL5Kq;W>#5nOBmLdf`b0P4og&_$zj|fP^8x7QiC4D5%Z~e=;qn%H85(h-=ODl!X*D z5H{25X-xyqaW1%jasJi3W7bXWe^qW)H^!vhfSx<1Wxf3ATyflSc04$mQvVXPKq_Xg zqN6^B6`9~L)GGuQ46{Lt)k0`W+hZ{FoLvuI*zBVnhhA&wU+eCMYF;R!2@UJdhtHn@ zsvS~ssoJgKo>DasWh_T@b~*^zCDpQ2gJW_hgF80JpfhQI6|6lEUh3Ss7H%4-O|g}0 zkN%WI6N;QG$t49k9#da>j#HY|=g)#XPmK!-x4GgTD1$znOxT%e|`-T5}?oYIP`3f&-2%2l1h zrf|`Ko`*btsg+DKsB4Ao)h(e)V;4Dt+G_xx#XLgELWJNxLz$M-N^`1SAw#U7-e!x0 z(+UJvHB4!1iTDP17`)c+ zaRTI&jSN#`t7AsP0EW3s>QLb@tW+K9iH3wVN|h>q50W5Sa7`jiwVNu0&-isloMI3V zjXDDqGquv=;>GURtUy_Pq3<>@#U%+v>#<(!jo=#AaPjn-fFKG(1p#cV(D^bjA_Wlw zV(kP>M|00{j%=}8)p*MpJrRCOXDW$UOMx;wVOz`^na2vf*r4J#H*lU+g=NnT98;ZF zRB`Elr+gG78j)2BJ2(Ai8P@cyQ}*LNYe913+`v!?gKU)?E~ekP+Mfi9FHtLGXnoN- zvtC*k*1x;w28Nx^s(m4n*&*ywL~BS&4k8^1$z&=E%Z_SKUoTh47YF}$_^gj))%Sk^ zl9=_^vE(EibOC=X+P_=_h(~+mIC7=;5=~@tW zC7FosmbWgFFHfGG91c#r-QI4`?LBgL_Ahq6cK3GOoyY%Y*oI_r=VIwds-h6<`x&3+ zxq;#7_>9Z*gbEtT#iLUoX*sAYK=K(AQcbjcUjqr9Fd>t9mhA6ipwtA(@YSzt&B>X6 zU(IIQQvC*wFe*#I(G{oQx(36}bmedyN}7!6E`qb(N0*{%Vg}-AO1G>n?d=8%cem z7T-5lzR8iZihh#k28Qq6ucr(cB&~aYxXX~VL(G1P=k`cWxmd7%l#%p(8Y>~A>Szt_ zUZ3@skPJx~E=18r^5WT`Vw}6*=N9WEU$Xlsnl70jF^bIQusE_A0#9IQ9kC3zJ`9%y zkd(SzQdl8r-B?`K^kE(fEw@I6ETUzDwzfv{nicVGkz8{mvp@_>E8W0ZIvde{L@9O= z52%1mb7ZSD0v?5P+-{je#mX_-trq=uNQV0>Z(R{dj7GFd6&pz%!srtsxw9UUCHK?C z(zQU+oMp!}!9l%ebk|3+?99EO?hWAmdp?G&N_NvJrsJk3L80|? z$P7N0bPk&jm5|x(p<$5tk|yGRW64w-lHuVGr-!F62H(CoK0AAS^52Kg&!3&N=r9V& z{BUk{B&~zT&94=b`}dCI_4g!9{`*H6eS7l!wEM&3=f@{!PrIY@w=c)+=x2lV4<|nl zHIn)L-_?=CD%wjj`wB!7RTqWjk}ar(Bvvthr*avVg{aXP zU%*vcvybwWkz5A0)_BbQ?$t*UtCZ2pZzM=9dG8jh8YIK6c9vg3`XG`;P={rw6p3;PxNFZX$(=gD=4d^Dt#}Tav310R?74wqo~>lLHfkfe zl*LO(qMw!?w+vq<@K%YS!JT5%2+8p8yZ}J{rSuvjad|$TDXA=KAD6Ru!vea)SiofUgraB@^IWSMvagR zWscA1I#bZASV;~h!vu+fE>G}q{Ubi>E9eau3)_(VQBZr;*EbLGm{OwS zFOlRP#yLkl2kz8BjX^B_b zxP&CYf@~J1>SyjhoI6W={O1OSJL~R3+5)Q%t4-^;sh=Lp4@Yv`h+!j=b%Cm_KOY-r2Vj<`9rn|{tBHcMwpT~o>+2COj^sK}K$Lji8? zFAElb(1ZqA!EqXzTfS3r#i9wuGo-;L`2>|~flJzX1r$wwcAWV__~GYg(20a=$J`H2M2-kQF3 z+NI+OIx{TNVsGG78&W05G;Z5Kj0;3=fzoGN87f)m5q-V+4xjaP*D{jrCwFiIx{N*_ z_>@oXv$B$NXC2A7{bopx?hDOcnct`QuK)8YF8w+LKGFhw*zpTI3#4@`QhdVz6h2qRV_jKK}C|?7GBJ`z8ytbV>2#^;4nvVMs1<)V{GoNd4K6B)_K# zT}Ad(1y2O8ux?%WG{hg&F$YaacgzzP>)uY@t}l2>NG_5+w%{pYcki-ieZez-@x^Lu zNPP);%K0RuaD>q=Gyj*{jqAi;;}*jDBWWQy@s-&5UhqZ_<{PEnU?e*d!f%2{+S9(l z*G^5^kNK=WCoLpR+ z$9}L<#DyqpMeDPxh2&zD#}+()T!>Go@~kg-N+YQ?njc?2Yjit%F&JcrSXt4Jb}eEd z+-tLIL~boz&khGI!W2s_5T+6NkSks5v#W*V>g;NvS7z4{t#K@d*FFE~_Bb^mxhA`g zc5l7adP4lmQAmEL@MQPH<;!Sy)lJteECai@*lLY-|6E%wD{11g%&`k|zzktC7Umo|0!Se1(~3P^ynMk@JMlsGQPN0FP-x)cd=5)@Roi zBuQ@1$$UdfHXh^0W5-f|PSq#~Ud1*Wrho~bU!gU9G`I1;6_RUuf3zSOW!bHVMbj^0 zgJS+sapd)s`P23x{Rq$cKIkn-vPjb8%D%RD0|P%Hu|iCL^5Ap~5tksS+(vtdH9mQy z^KuL0!aFC#y#e)|jhU}xC{8Vf?qC5=39$C?tZSkWMLKdnuA_+gt4;i8V4S13 z3Y`yo%@lY{q9?mNHWAM=e`o4$i<0-jNVbQLxPc$&yl}m?5dKKGEFkw7kCke@W*Ds4u?S&j0*%mRo&bGIW^qWj*GOmZe~SYq;(zsa;=#@Z zYYpvxF{Orv&6zNaTC5|(z)r9Clwtla%yU-t?Drh!FvJVil7@3DNlYGzRtKeLA=TPh z7G+vkG&B(uO%VRZY!J63kvj%EJa(NJ-@sR2U9kA8ulitzE4LFiys}#Ob<_H>N@q zburt{>K}Z4XGngXA$i87nKuTBgl8qGm%%%TZi$j2CA+g1ekOupcrEAue`$t4L@_dAcw zU?I*ZS5*^v?wX7Ww;zyg1nFS6CBex+5=qBtsCLV*kUrW?pgGl(oTv9B_kmd zqSXWSRwg_Qe`zAR!n7)=6x|0_vs+-r6O+8oo0wO`0!rwFBbLxL7nZlx#uhoE@$&sR zBolP WSnwmq2X%tYpqRhrM3a0HzTQ#&aJX_!EEMwBnZFiVO8GZLlx9-&TUVNzT- z=9sXM^c?5xZ~#xWxv4Ba)gYB~WI084D%;w)RPwc0e^hN-L9v_8lbcztFlYf&%b+$G zm|SM(KcRgnzqtIIMDwA}yah*TlF&$oa~RWWJCj&;DJ~Av35&$4S#t_DFxj(3_klih zcU6aCE6=;t49^8OQ`ewn(+>xx$R$`E+9|nGGxxk;#Gf<@*;K{)YVI0!%|Jqf3a%c! zLW!7Ve|B3H_Z;D9EVdk;%8*5vGl#|{2PQcCc3=jjp7hGg7%E##ExxM`H6{;gUUtP@ zai6sYHJvFG3ojb*maR+mCJt1+71pHv28LL`^F{`>ufRp!Y!$91*Sr1d+k)kG!+FIT z>v3%=d|e>nInH?@WLMMgiiz@5kz5_`FX2U4e*r#E5-MUI1&vxYt`0{1%tNN-@yjqb zT0TAF>0B_Mgn2?maz$8(YYc16X{Wb?+CF^ElS{Nl=_D=*QCb6P!9zNW<@}f>!|m*H zcnfNa^RQL7D5Wdv%}ROaFoLZ2JSu~LF-wHZorZB;BX|pt33GWfOL2OJdbA?Baoi*V ze?qR7G-D<{FNG=7`TvMSmBXxrdCNMNQlNvo5gi*8?IO_}5=sP*v;_~No*1I%z+*-+ zwIHH#fnL$X>wM)nCwb(QCW5x)pei`;blfP94WpG@R=4x5E0Zm01$R6+(h?L6krjxP zYOvt526)edB0;0swynbwcDR{?^Pi4hf1e#bKWX5NGb$Cs>L~WL1VY>-vxG<&%lwt| zi<8?<2E!|o6~ZZq>yu^yrgoVoP;qJclsiYVE?mGQ5tpJ%0tLRBcCMLz-GKTbNvLZ8 za5a<<^aUMv&Qo_pCoJ09c63Zu3B$zLg<-sISwY7{L?;-q6{qsog%V(*Oe_E@T zX@bdG%lM4)Yu}E-+eB_WrqSFwd?>tW_3osv6m!qzjXTQhv1sSf9dpp=~(Fe(s}>B z<2e6PlDpC1>Ye;Ti4%WsN|sAv7X*X!AdYvY9aOl0_PHw_%7J3KKV z=??VB=|s}1CkLYpV;N1eTwyM9PnvL`c;bbskG4{(KeZEqUX}EB>$EEl$-FR&@l?jC z)EPsq8#6_Q$&+%R;Hp5<=~yYjm=ER#ij|nvFT{n3Q>&O^&eOs|q*O$Of2^WfB`WbY z%u;{qU^=l9^_dx z55}C2NHQY7SBvB+HH#u|(zjOjI98R8xm?z?BeI$lu7rCXqXvmu4hVfv#j4pBSnStL zJ~xt3weP3CEcnH6!H$;&e`Ln{*RGwy^peiu^jIwx!<-mdks?^JS}2ASU%bAgbMH5F z*>f?8?$e_IHlef0ArOUaRej79v@s=^JXlW~CV-nGQY*b2UYBoQ9m;pFTzvTx4ti(IN1pV4`sB8l}T7tn>$#M=Xpc&^7I%QN(VQMnVCre}kgfDxno@)nwcP)KVNSo~SYut`MQ->ue5=Sx66JBBx!+yHji_47N@*Z;g4!kYvH#7taq*&kppg(Wd}) z8s>)0027GLl=|L`FcBC$jU`GID5Q`+HPP^U@I9(iK~VBOfAaqM)8Wh0!za&9P=WpC z;GbxZ{bs1MpexZRwSi7aE6w8BMXXXb>_tOp=R$Ah*P>CIZA;g@Oh3yQ*R=Dh_ba-m z9O&OW+tz!denmW@rPpaPp{;v7JF})S8kMuYSSNmHp3}s4aS6(L`PE#^bo1bh*4@1v z;ccz?qLp09f2Pb{71C%Tr|=E*aM3Cn%`QT^aHQ>n#e9%Wm7{n^C<(bH4ce{P7-8S(@8iF{Ua$IZueZDV z#m@fzPH%Uwx7U08MQ`Wf{{GGv(7TJymp!SFB>AHEDZzbJk^7T8Gak^st=D{>wx6HR Z&*$g!^KbF|{{a91|Nqy>G9>_}0RTi3sVM*e delta 18899 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 diff --git a/deployment/charts/quanxiang/charts/mongodb-13.6.2.tgz b/deployment/charts/quanxiang/charts/mongodb-13.6.2.tgz index 3d4c932c35d141b88ff6d5f5b23022d593e74b8c..29cd9962e02c5082f6146f8fd5784083dab09541 100644 GIT binary patch delta 71990 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

4C$ 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 C$%2b@&ZHzC^_P>!;BH<@`37q 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 BSX%%9 literal 0 HcmV?d00001 diff --git a/deployment/deployment/quanxiang_charts/kms/.helmignore b/deployment/charts/quanxiang/charts/kms/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/kms/.helmignore rename to deployment/charts/quanxiang/charts/kms/.helmignore diff --git a/deployment/charts/quanxiang/charts/kms/Chart.yaml b/deployment/charts/quanxiang/charts/kms/Chart.yaml new file mode 100644 index 0000000..4b59dea --- /dev/null +++ b/deployment/charts/quanxiang/charts/kms/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: kms +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/deployment/deployment/quanxiang_charts/kms/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/kms/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/kms/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/kms/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/kms/templates/configmap.yaml b/deployment/charts/quanxiang/charts/kms/templates/configmap.yaml similarity index 71% rename from deployment/deployment/quanxiang_charts/kms/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/kms/templates/configmap.yaml index 3355dbf..33beee1 100644 --- a/deployment/deployment/quanxiang_charts/kms/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/kms/templates/configmap.yaml @@ -29,7 +29,7 @@ data: # generate secret key by this key # signKey: A)uQC(M1]{EHUs9}w,V7ogP!>$4T%NrRF0OdBD?v3;^~t*hYaqJx2'8[m|_ck<@6 - signKey: clPLm)^tq=|&kT#[+-2igo%Y@F}wN5SX + signKey: {{ .Values.signKey }} # -------------------- internalNet -------------------- internalNet: @@ -38,17 +38,17 @@ data: # ----------------------- mysql ------------------------ mysql: - db: {{ .Values.config.mysql.db }} - host: {{ .Values.config.mysql.host }} - user: {{ .Values.config.mysql.user }} - password: {{ .Values.config.mysql.password }} - log: {{ .Values.config.mysql.log }} + db: {{ .Values.mysql.db }} + host: {{ .Values.mysql.host }} + user: {{ .Values.mysql.user }} + password: {{ .Values.mysql.password }} + log: {{ .Values.mysql.log }} # ----------------------- redis ------------------------ redis: - {{- with .Values.config.redis.addrs }} + {{- with .Values.redis.addrs }} addrs: {{- toYaml . | nindent 8 }} {{- end }} - username: {{ .Values.config.redis.username }} - password: {{ .Values.config.redis.password }} + username: {{ .Values.redis.username }} + password: {{ .Values.redis.password }} diff --git a/deployment/deployment/quanxiang_charts/kms/templates/deployment.yaml b/deployment/charts/quanxiang/charts/kms/templates/deployment.yaml similarity index 92% rename from deployment/deployment/quanxiang_charts/kms/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/kms/templates/deployment.yaml index c8ce8a4..8f38fcf 100644 --- a/deployment/deployment/quanxiang_charts/kms/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/kms/templates/deployment.yaml @@ -2,7 +2,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: kms - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: kms app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} @@ -38,8 +38,8 @@ spec: name: kms defaultMode: 420 containers: - - name: container - image: '{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }}' + - name: kms + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' ports: - name: kms containerPort: 80 diff --git a/deployment/deployment/quanxiang_charts/kms/templates/service.yml b/deployment/charts/quanxiang/charts/kms/templates/service.yml similarity index 100% rename from deployment/deployment/quanxiang_charts/kms/templates/service.yml rename to deployment/charts/quanxiang/charts/kms/templates/service.yml diff --git a/deployment/deployment/quanxiang_charts/kms/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/kms/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/kms/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/kms/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/kms/values.yaml b/deployment/charts/quanxiang/charts/kms/values.yaml new file mode 100644 index 0000000..54895f5 --- /dev/null +++ b/deployment/charts/quanxiang/charts/kms/values.yaml @@ -0,0 +1,18 @@ +namespace: "" +image: + repository: docker.io/quanxiang/kms + tag: v2.0.0 +imagePullSecrets: "" +signKey: replace-this-place # 替换此项的值,尽量复杂。 + +mysql: {} +redis: {} +service: + type: ClusterIP + port: 80 + rpcPort: 0 +app: + kubernetes: + io: + name: backend + diff --git a/deployment/deployment/quanxiang_charts/message/.helmignore b/deployment/charts/quanxiang/charts/message/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/message/.helmignore rename to deployment/charts/quanxiang/charts/message/.helmignore diff --git a/deployment/charts/quanxiang/charts/message/Chart.yaml b/deployment/charts/quanxiang/charts/message/Chart.yaml new file mode 100644 index 0000000..3b914bd --- /dev/null +++ b/deployment/charts/quanxiang/charts/message/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: message +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/deployment/deployment/portalauth/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/message/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/portalauth/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/message/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/message/templates/configmap.yaml b/deployment/charts/quanxiang/charts/message/templates/configmap.yaml similarity index 72% rename from deployment/deployment/quanxiang_charts/message/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/message/templates/configmap.yaml index 2b46602..10f637a 100644 --- a/deployment/deployment/quanxiang_charts/message/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/message/templates/configmap.yaml @@ -2,9 +2,7 @@ kind: ConfigMap apiVersion: v1 metadata: name: message - namespace: {{ .Values.namespace }} - annotations: - kubesphere.io/creator: zhenlinding + namespace: {{ .Release.Namespace }} data: config.yml: | # port 端口 @@ -53,25 +51,23 @@ data: # -------------------- kafka -------------------- kafka: - {{- with .Values.config.kafka.broker }} + {{- with .Values.kafka.broker }} broker: {{- toYaml . | nindent 8 }} {{- end }} # -------------------- mysql -------------------- mysql: - db: {{ .Values.config.mysql.db }} - host: {{ .Values.config.mysql.host }} - user: {{ .Values.config.mysql.user }} - password: {{ .Values.config.mysql.password }} - log: {{ .Values.config.mysql.log }} + db: {{ .Values.mysql.db }} + host: {{ .Values.mysql.host }} + user: {{ .Values.mysql.user }} + password: {{ .Values.mysql.password }} + log: {{ .Values.mysql.log }} redis: - {{- with .Values.config.redis.addrs }} + {{- with .Values.redis.addrs }} addrs: {{- toYaml . | nindent 8 }} {{- end }} - username: {{ .Values.config.redis.username }} - password: {{ .Values.config.redis.password }} + username: {{ .Values.redis.username }} + password: {{ .Values.redis.password }} - - email: diff --git a/deployment/deployment/quanxiang_charts/message/templates/email.yaml b/deployment/charts/quanxiang/charts/message/templates/email.yaml similarity index 75% rename from deployment/deployment/quanxiang_charts/message/templates/email.yaml rename to deployment/charts/quanxiang/charts/message/templates/email.yaml index 9138bbd..08e9474 100644 --- a/deployment/deployment/quanxiang_charts/message/templates/email.yaml +++ b/deployment/charts/quanxiang/charts/message/templates/email.yaml @@ -1,9 +1,9 @@ -{{- if .Values.config.email.enabled }} +{{- if .Values.email.enabled }} kind: Service apiVersion: v1 metadata: name: email - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: email app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} @@ -27,7 +27,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: email - namespace: {{ .Values.namespace }} + namespace: {{ or .Values.global.namespace .Values.namespace}} labels: app: email app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} @@ -60,15 +60,15 @@ spec: spec: containers: - name: email - image: '{{ .Values.image.repo }}/email:{{ .Values.image.tag }}' + image: '{{ .Values.images.email.repository }}:{{ .Values.images.email.tag }}' args: - '--port=:8081' - - '--email-host={{ .Values.config.email.host }}' - - '--email-port={{ .Values.config.email.port }}' - - '--email-username={{ .Values.config.email.username }}' - - '--email-password={{ .Values.config.email.password }}' - - '--email-alias={{ .Values.config.email.alias }}' - - '--email-sender={{ .Values.config.email.sender }}' + - '--email-host={{ .Values.email.host }}' + - '--email-port={{ .Values.email.port }}' + - '--email-username={{ .Values.email.username }}' + - '--email-password={{ .Values.email.password }}' + - '--email-alias={{ .Values.email.alias }}' + - '--email-sender={{ .Values.email.sender }}' ports: - name: http-web containerPort: 8081 diff --git a/deployment/deployment/quanxiang_charts/message/templates/kafka.yaml b/deployment/charts/quanxiang/charts/message/templates/kafka.yaml similarity index 80% rename from deployment/deployment/quanxiang_charts/message/templates/kafka.yaml rename to deployment/charts/quanxiang/charts/message/templates/kafka.yaml index 7b368b7..4c3ce08 100644 --- a/deployment/deployment/quanxiang_charts/message/templates/kafka.yaml +++ b/deployment/charts/quanxiang/charts/message/templates/kafka.yaml @@ -2,14 +2,14 @@ apiVersion: dapr.io/v1alpha1 kind: Component metadata: name: message-kafka-pubsub - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} spec: type: pubsub.kafka version: v1 metadata: # Kafka broker connection setting - name: brokers - value: '{{ join "," .Values.config.kafka.broker }}' + value: {{ join "," .Values.kafka.broker }} - name: authRequired value: "false" - name: authType # Required. diff --git a/deployment/deployment/quanxiang_charts/message/templates/letter.yaml b/deployment/charts/quanxiang/charts/message/templates/letter.yaml similarity index 93% rename from deployment/deployment/quanxiang_charts/message/templates/letter.yaml rename to deployment/charts/quanxiang/charts/message/templates/letter.yaml index f0dd01d..b5d2fed 100644 --- a/deployment/deployment/quanxiang_charts/message/templates/letter.yaml +++ b/deployment/charts/quanxiang/charts/message/templates/letter.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: letter - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: letter app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} @@ -59,7 +59,7 @@ spec: spec: containers: - name: letter - image: '{{ .Values.image.repo }}/letter:{{ .Values.image.tag }}' + image: '{{ .Values.images.letter.repository }}:{{ .Values.images.letter.tag }}' args: - '--port=:8081' - '--message-server=http://message' diff --git a/deployment/deployment/quanxiang_charts/message/templates/message.yaml b/deployment/charts/quanxiang/charts/message/templates/message.yaml similarity index 90% rename from deployment/deployment/quanxiang_charts/message/templates/message.yaml rename to deployment/charts/quanxiang/charts/message/templates/message.yaml index 71fe12d..3a94c66 100644 --- a/deployment/deployment/quanxiang_charts/message/templates/message.yaml +++ b/deployment/charts/quanxiang/charts/message/templates/message.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: message - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: message app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} @@ -30,7 +30,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: message - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: message app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} @@ -68,7 +68,7 @@ spec: defaultMode: 420 containers: - name: auth - image: '{{ .Values.image.repo }}/auth:{{ .Values.image.tag }}' + image: '{{ .Values.images.auth.repository }}:{{ .Values.images.auth.tag }}' args: - "--entrypoint=http://localhost:8081" ports: @@ -77,7 +77,7 @@ spec: protocol: TCP imagePullPolicy: Always - name: message - image: '{{ .Values.image.repo }}/message:{{ .Values.image.tag }}' + image: '{{ .Values.images.message.repository }}:{{ .Values.images.message.tag }}' args: - '--tenant=lowcode' - '--config=/configs/config.yml' diff --git a/deployment/deployment/quanxiang_charts/message/templates/subscription-email.yaml b/deployment/charts/quanxiang/charts/message/templates/subscription-email.yaml similarity index 82% rename from deployment/deployment/quanxiang_charts/message/templates/subscription-email.yaml rename to deployment/charts/quanxiang/charts/message/templates/subscription-email.yaml index b637d21..08f8284 100644 --- a/deployment/deployment/quanxiang_charts/message/templates/subscription-email.yaml +++ b/deployment/charts/quanxiang/charts/message/templates/subscription-email.yaml @@ -2,7 +2,7 @@ apiVersion: dapr.io/v1alpha1 kind: Subscription metadata: name: message-email - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} spec: topic: lowcode.Email route: /send diff --git a/deployment/deployment/quanxiang_charts/message/templates/subscription-letter.yaml b/deployment/charts/quanxiang/charts/message/templates/subscription-letter.yaml similarity index 82% rename from deployment/deployment/quanxiang_charts/message/templates/subscription-letter.yaml rename to deployment/charts/quanxiang/charts/message/templates/subscription-letter.yaml index 412e0af..fde316b 100644 --- a/deployment/deployment/quanxiang_charts/message/templates/subscription-letter.yaml +++ b/deployment/charts/quanxiang/charts/message/templates/subscription-letter.yaml @@ -2,7 +2,7 @@ apiVersion: dapr.io/v1alpha1 kind: Subscription metadata: name: message-letter - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} spec: topic: lowcode.Letter route: /send diff --git a/deployment/deployment/quanxiang_charts/message/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/message/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/message/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/message/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/message/values.yaml b/deployment/charts/quanxiang/charts/message/values.yaml new file mode 100644 index 0000000..eb22db4 --- /dev/null +++ b/deployment/charts/quanxiang/charts/message/values.yaml @@ -0,0 +1,28 @@ +images: + message: + repository: docker.io/quanxiang/message + tag: v2.0.0 + email: + repository: docker.io/quanxiang/email + tag: v2.0.0 + letter: + repository: docker.io/quanxiang/letter + tag: v2.0.0 + auth: + repository: docker.io/quanxiang/auth + tag: v2.0.0 +namespace: "" + +kafka: + broker: + - kafka:9092 +service: + type: ClusterIP + port: 80 + rpcPort: 0 +mysql: {} +redis: {} +app: + kubernetes: + io: + name: backend \ No newline at end of file diff --git a/deployment/charts/quanxiang/charts/minio-5.0.33.tgz b/deployment/charts/quanxiang/charts/minio-5.0.33.tgz new file mode 100644 index 0000000000000000000000000000000000000000..fdcb9f57b5ba06d043deb18ed54f3677ce29d45f GIT binary patch literal 19289 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 Gz6SszNsILW literal 0 HcmV?d00001 diff --git a/deployment/charts/quanxiang/charts/mysql-9.4.6.tgz b/deployment/charts/quanxiang/charts/mysql-9.4.6.tgz new file mode 100644 index 0000000000000000000000000000000000000000..131a448727ea10557bf1ae21875bb85ab7c9d548 GIT binary patch literal 45761 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%0D(soaXL8O*}kND+#qRy3dymk_|7))(IxL(7yXFO6 z0~rluEuTDCmtF7TcTQp<-?`8$(g}$^bX1bfK_Uj`K*QX9#t@fV{?#vo384chs)u^z zQr9?D6{_Gio$f~cQu4<$0)F!PfaGIwlOzxA*|5#lWXl@1Y zZ%BGU2$!Kp0jOUyV5$OL7uaP0lXDalph^Lf6%$yXVY-R_hjC$7bvk8KCI#yC@a-sJl zOmdB0G$S}F-BT*);!2iI7y&qqD3UuF(F~@M`j>JhcNK}V8_kr5F2S6azJHC(4q$mS z69~M$cUEGFPROdVRRYI&;YRX)545$j2uP8IkBr=kpuf6JLHFc&SPC_;?M zO*g>;iss}_*%eVvlLZ)yiJR#ip0A6xMqdy8#-1rKRJ|&v$&$kq zatX^&usrahX0a40cbQbAA<4?MM{MNyI}RZaU^z|MZ~sVxNQZ(*ydUE@vhk}e;jC}%m6sbq%fW6PJ z2ejjesR5NId&_rAjh6jQ3>RHII9{qtJsAP?lRZt=Bg9-Au9I!+fg5yPtFjl4nyDjE znGu)3!iC&|#-*(@YDnn5T^a=&Y7habzFWi%_@U?LU9sFC#H5 zAb#(vEb=nF`x#OOUP{I7i;*_runh4sE-|!Nt5Bh#n>b>V+2!j0nowZnHywfg%bb!7 z?Vdx5nM;I$5%Q1Pg-%~L1;S`##Y<$!6=Zf>DZ1@+;;N4Cuc4&hZw{Yo+`OK@GLv&5 zLOM>gmW2VFCJ@h;cexax`9M1!%RrK{)zB`wRirxS+Bnz5O$UZE6V(rHN`e$UlAIgq zB#|NfJ2G(xnrD1*hN-m7#FSBOeq7c z?V}V9Wj3Y_JL@)eEFYgkK9jzb)X=7V$^xN$tj;BHq8!d@m!$+?x36J!ZQ0HgQt^+M z(yA~q89RVVjG}?Rn&{II@s5+yLv649Py5w>SatNli2k7OtJd%DfcG;T&CJPt2I55u z=QvX5ei$aHa;O=2d8)AhTk6QW+EN6D&a|OVx^!dn5^=L+j6m$z- z**c;_0Jf&tffy$z|GM1KhcsynNLoVr@t-eu#Aoo|z}pO^mmEg7+fH{?v!Jy1nH{dy z)@6|#FIEk^ZCHyqYi(NERIf=~3jnD%t;zyf*lD$dp){13nuLY&FN!&OTZ(g|+~VJB zo2+$t#lO2l1OJXj;M*T@mj+D0LlOB4>kXj9+vF3Q?ECx_)<1Tf1+V7?f@ zEOW4J3wV%okZP6r&WWpOEx}5QStgX8Gu*xE^Kx5kt31SDx6y0_s6z5s*eclQitPs> zJeaAvLG;8@9U ziX%SIU?zl0ej0WTGB)(``n*w+2Mq59w6?!i$=@SNIeB4`mo3Z=f$P6nw^#ZW>Y zGQtqpN(r6IiCTJ2inFUXdbYVyPJ-=O^VvoE`Lq<`= zm4iw!nTgfMIf*x`$?h=aIZOsPV=^#Re-JYL0lT(%g+I=;(2=Lg!((@?&LB}5HI*8r ziR=MnjfhAy*D;o>Uf{#My#|6bOiNJyfnc17bxC1yP?90aD~y@xVrG^Ov%{2JQqWB` zzr+uVX7wLcu@8mqonc0EX?%n4^LVQKTxGcOGP^%CPi<9c?*_%=(%%%1gMOxXtn={b zId4}l<^c@hDzmhZG#ss0+A9)pnJOZLz#OM1MRM5JIK}gP4$^!+MsznrG(stdQ{<1) zRFjfUYetbwQ)$A79iNZgh}oD3paVa=OUrDvui=N~5t_q=O6(OQke9$5gq&uYPD<&- zl(lt-it(4OJRR*XCTFRzAaj#i?pWD=IlL7^3PmW^jwurZX(gldBr;Irxthv=nYV5- zgW`2Pok8)*O=wWO-T^FucgUB?pePe)OS=tEr33Db?69(z%62X9qMesUR;%tomB9a~ zr|(M&R!R0y_WEYiJ(O52m+)a-e7q?iN@N<7J_Opnue1+#$8}1aP~!KLI^ijG!c*#m zr_>2cq)sTc&8o>09QF8x(kGNute8Ndv=aU}DHKYgS4pB!Qv4XwD7duv@&h>dHm6ds zjEp~IdVuC+3YBgTq*JJ{t2Lp*AC_k|>;!T>oGP!}I2`Q(qjemF%I(2JVvXp^C@q2_M=qX-WA|MP;?5 z5AA3)rhTxZLMn+LO2~hn)DIPMP4b5mbDgig4jwfmgD4^u!^^z~OakF2X#F%0O=8uO z2*Quj22w$E#p#cd48roCE}0IZ9_rkd5W+b-)R6cgfYSz2KX}8lK~v<|{Um?zQ}{6H z9|CRH6F^vA_ooyPUp@tdzu)RfAey>ujWiH}=4*){nwsBODu{p#m&qU+Ww&EGh(IHc zHz7o2(%V={2xt4PYf=a=GMh~c;hBqE;!!_ByJWVAdOP)e5sl5Qm^h-|u0M4|W8055heVyaY8Ht`y6!2RL>(({ zLWvT!zi>*4IP^sIZhoD?0!xk0oY6owycY^1^4PP7hD=B$1`6!QQDq%HKiO(Rkho-7IQtw0pj( zJlsakiS(?x47ehoN(03NI_h#qxrP43NtLjs>^rEEoh_!fJ(rjRi=y*mm6D% zj;kf61_ART!HkzDX%cPwIy&WzGJ$|vo>(g74YJ->=D%mpdfIf-s~U$-&Zp|Gi#_t+ z*ab_v3tyMnO{sT<+k{;HywuArxzV6O&Pj|Cx%HT3$wKcO%Iy&CGuMf{#p+n;(87+7 z2o=_*4(U}EsXBcq&CwaWLk0`u0oG=zSSe^8VkWx)rA2@(NrwsnrC?Ms2~hyaq@iK9 zUcrP)vuB}~yb8ir6-5vu#`OUk+4%Ob7?(CL6vG_}fuv^jJ%c(DdP>X`ua-X) z!ANz}+4oxTzRx*eWR7H7l^yUN=`d|sMqh=XL!wE7 zO@}$6j<8Hh(x!D4hs2VDgZ~SPI*#D z$3hi*X#&znpVm-yMjFTv6aC(Z#t4{vMEc(Wo1sLd-r{gN0{i=e7>zMZ2mAX2`a*ei zR6i81_mVLq@M`jgaCv?|Ew*+%TbKrEF%KIYH7M6=)k3A#Dtk4jTV3eDO1-7kq6<-Lw+hgQ(RnT= zmZqy<6H;jP`d>(msbp#cOQ5tO+Z*m54fh;ncKoEw?q8XiEV*?Z!u)|1O=_nIGgk*j zolx)9^9~eg8H)U$@~nnppzo}Pk#;A(BM{GFIo&LZUfK#T1lC&ed#YB$IKpsjci=B7 z72L0lJ>mwv)ni?JaVY}C2>gA2@2IvZs5eSVeJ?tLMHI?hRGj8Ixl^@>0@?rg5e$Ep zD~_R;L!UqQ{S(gzPT>iivZ2Wbt@d1H{#vyz&LGnP@Jer77px$uo!Qyn{bd8C&waTj zEIGvDd7R}Hc4z(+T zL*7zQqprKIQ&~BSt0jA<^3go&T5hg$X9SC8lthTJ!qeKN;BbypnOU{DhRVQ75z9!* zP=^YS{ z1lK#)dk=9NQ4^e?YgM{KL7Xx!lSDL^#c7N_VA7#^*`eJ_CM3FTDW}gI$n4Y7v2#5~ z^D&~=0eO%q>Vrx}eU(Yu>mO$bQa(n|(-+03Lb996aJ{=*hSZA5K}~;p3MwLWiW$SU zl!A88Q}&WSYxWXjODvna#Itw~WihEYu|y7&4(+Uy&18S?99Y1%;?Vde z7aJ?4EAdy~RI(C3^fgkI_yMk!sKgI)?KCBRuwN!g$^Lt!Gb09`--NC5Dc%06=V00YGuAtui1HAyiiw0VUe z5sC=27WxCT%UtooXlT{g&Wd+LmnsIssR~xQbiRTMV_M2|6%mCQPNxQxId@%P^tMC@ z)Q%_nLOlaGl^g%YKkWEE0Zw&rhlvuiFfNQ?6Tz)LsLpX81IcqfB!JRyWGrI@oFm1e zc@>{SQtddWQ&fhvaUvrlpxTT6jf{0@UuwIuY{X0}-SLtqV(wt#aH@C-xn`8r*f{9XqD@?@yJQWSw>FK7_8lj)1Jp)F4LJ8}S4L4JdrHQ* zU#P!TpgAjIwWRs4%tvz{Q@y^hsC{j}=|D41r-)UKH$5EDHT=7iZXGCgR6_AyMMJldWj2e{B6F8h zgm&i;r^N>k!OyIB)v*17H2<09vZg$uT>f;ANH`~zJ1}ELQbKi5xEYuByJBC(WJ$3G zCrV=(2jd*BDC;hz%XI|$JMHGqAk)EoR*alH%`{ee!V|xIDqeB65eQ8e->O z^-^uIL3n)~VfVdkTc!=cw%p1<^aN2pQY*#58F_D|^bm_hIs$OaP|COR?Bj1_{9Rw} zWc5FT@4f^3+g9O;P=wEI?@dzA`2ZNYLsTA-dk?9d*+hR;Tb5uBDTeXb`dHhYGFj%8eC6Qd$D5BIZ$5tpUnx|E_Lt9}#TQ}o#N>VYwTnkSSFYb0NL}2q z2#R?6zdb#V_EDGjsW8}~-m&-@x7`kqA9G#3DJtGt_0?swvc7tcc_Ke3 zhrLt1C^R8--dDbn;$4hbM6nEK64mS1h{?=M2}zN6gX(JD_hB z?knT|^Nyx3=QAH&7GGStPMo`FT??m~LT!h{62F`wDlZb-0ey3KZU5JzES^|M`MXAc zQSOE_y&>2i0r0V8gG2!Q3O*M#%wL~N%4R6-+E`pRW4{-5Am@n6uKNWJem@!f-@U=# zfBm?>bA0rr&6eokGyykqPI34 z1tf1f+4^0k+bJM<+pz}sJBH{w5>i5Hq0K6}3CXnDZKkz0+PzJV2}ux4n^~*;uN8^v z*N3O0E_L9*QX11lt`$7b@|aLUmX(WZ9x_xAQ{pJzCZE0aO-O-{rH!D>x40SKLABxJYV zL%W7UmCB!cpC*khN3P=9So9;_UXD~Z6;34R}17Ho}J zNB`ACpR<-*KOv-dz^jQl2`&nvdBzuKnD!fGjN#wwwqEnx<|0?e=2C#HRq*Kk;u}S2 zETz295*+)4S-pRag}~NjS$%z%V!_M)kGNicqk69tqqPLwJN*`MdP_~fWnA~8or0Th zM0|Y8_mNM+1v~#(({Pt-7ayN2Jo<^al!m9N_-QKs^H0T=_PdwKxF`Pq`SEOtDF44n z&Bb=#yuEsPIpiPs2HR-%|L+|?KYm{K{~ta1{~zKx{m0406?k*<`sE0G{0N4pGf4SR zric6dxu?GV{PN=R)!R3AfuF_TAgL&Ga(?bBagt?Lq24#&nDgE8Bq5jChu+Vy$#*B} z0L;J`36&kAEFlXNgKxg+^*(+a06Zy9PR1BcQ^GioUX!@o-2eQ!cU1tIK>-P+B_N!F zvZBm;H3TO~q7U4vG)1b0N*x*NG)JhoNT`5G?ht)XG3O|iksG6)ybV~E5*!!+oJL6= zBVp&v=Oi8SEYUk`S_y)!7)RV_r4VVR<-Rdrz*pPg6G(9y3+^2Wnt?o_xzT3jkF1FPYg(-FqSikUUVNj-*-n9SfPS z_w@Uf*x2jom?9>zK+%ktv&$m~h{`Ofm(4|nNd;uswY4F;i-y*bY#p$5Mr7vI&!0!u zH`A2weuB@Rjfz75E-KiYm+l^-8nu$P%kt=4ow_n(>I2Z%d;^1~5T#Ph_Ffi}X`L_= zqCM4mL8hd{jH|$^h$5joFifm&eW$lbMsjPd2f*w9bNRo1y1sb(_Uiil3zcG>uOYpn?M|nJ2vB)U?e zGwp-HfX=~S!1)3Uu=s_fUit3pH|P%0ufafN&;UM;$S;N&D`~+2O7HwV>3Jzno~jwH zP?P{141vo~<6k#{>RS}ScvnooXuIH;lGDNL;k5)95@pn01pGHiSCrEP=m4hugBQcS;ofk+L-k#gOQR;E?ijj*363F03Ys=q z>cyfNif%7RlHhcD1*c`f0``|)^jS}J{eL|}NrosBi-%3M(Gvf+fBa&vy8eH0bo{jb ze~9Pf$K7wh9iES5hTsWK5MN~IySZRXG(#is&8|^h>VC!Wv^rS95EkVv?eSkbDvqjI zE|02x0-WY)1db2opLl+mPbT;S=nqQV5{5V?KQmKGdl%%d3qpA5VNebARYs)pwfemc zIwEamzjm~pB!26o?|@sIj1qmYWe#xQZfRJzLj(uXu&z&f0PxyOIFtDg!7B;O7(8H;)cTcQ(l=ZVqwwC2e)T+O8|qI;?@HJNIksYyp)}UPwepfymA>3x8Z&i0h0a}R@`B?;CEhV-xyC6Q_Zu&Pjby+)5ftSrX12-a4orHIegZV~GMh?%dl7Ow{F9}=_hOfy(&1}NlA^Q>LS zLi|$&6=8L0vZcVoiEU2_bxOjV^!NcMh&2dF3#H2JDev=>c8Vk_LR2gsz%5z`BgVd! zUh`xNPlU}PU$gCB<$-xX)i!TvEA zs&hr#;1j?pcl!1#GX6~#PYAiqGtj@=@5``L33phYb(eo`%WaveU`rSkd6OwW)tBKv z(E@w|G^+OkwD4-k^R zn(r{QxY6gt*^m~ctLyDmYPyS_RUm{`j9#feCG!j?@`5XK@?CIBo}FVjohHZ}WLL>4 zBT;YyaT2tSt4>$C$zJ)IQ7qZBxFS98A(yfN1(hBLeoHKaOd03=|KIV8!^5Zf{~;bNmZ4~Z+V-kirh9z? zMSPHdGVgRO;}J~ejcaU;_0z1sxmn)`%6u`5(#Z&X8m!Mce;7$4PWQ37@&|ZA`rnO9 z9IQ1RwCew(ivRau|Hae!|A%=zF<4H}ryJ1Vj|W|ON?0#e^l7&E%gz?-IFw!SE?XYj z4Ilhf{E;F3pT*+`+yC2pzF*t_JAB&ze~>2-)-1YTM~hc6O zqq$6%{e2!!5r0}OJn8@CeS{5iJICos5g;k++i$#{JAbt%COI|Xhj%HgH0itxH|nYC zG|PgHP@lYa^ni92+`qyM_}6|y^S`{|f08E*tse;3JpUgZ@7MPKUK}1ht^Xe6S!Qat zWg;-YU+N;4PxJcIyuQl3u21FYD~mG{zlJHCqB%;r+7j|lrS)>IKz!M0w79|T&9cKF zV0GkK3^}^w6mm3OsG{yW)s>aKwLtZzegVbKp=O;msDbbPIcrQTxv5}k%QFxxpYJ-} zTZe61(sKm98eVDShTlVm&LN+Heqal$zb(6v&EUcFW0udW=S3`(x9biYvFzNk$SfU0h}q!T6MV=200ZrisOQlWh&%K*YiZ^sHP1 zFl4eS-vZV=MIvxuJp-^i#_6t1q3gaM=X*Iw^I6Bx_NYLCVRdfdGhiz!wWWi>Km$YE7dMRBpl9|5=5YthbrrEaMNmXD>g zz(GoKTYd1`6I}oVTnXL03$E7Ow0EHbeI@TgR-Kw75(>% zcf+@3ho4Sr)3)KNB`U%$C=6leokff6aDxg@8VkK_sOhczpAq!9NeYK6>Ew(~HN<4c9RL@Lm6_ zkDi6iXz;n}C>IZ&fM0$Ag9-50l9Rls3V!|de*iv1sRu?4gRizC$bt8|Hwm!6?SV4E zo|kf1$y+1MEu+?Lav$wRKUcF-bagE#DZW53#(|+joo|~QJC#;9FnC;C{iA0S^!SGl zt=`}G`m)Kfl?iaqwCc__LbSS3uR< zUqZyl0uA`rT{@!5u1eGr>POGlCEbfPpVe}AYE;QoE*AUdlw~M3PONp8#y?vF@ZQ`S zP9y91Ha>PrR_1WoNf-;7w*M=aGcFMZ;M8ml2dHh!J(ex7cz`}+gmOgxw3}h|d!+7f zFYJ#QEb%zv2JSbua5dX;6L#ZzHe=0RJUh8MxxRe+?&9?2^_!E|FTd*x868#3#Q)q% zNCcA^VSIFWxOcq0+gHp}qyE~AddYtG(v3pH3N?O0r-foScciO-yPBR&9?Y7e26Z21 zkxsH~V|^c{p>Z|GpR=U$f?6)_3doz{e?+{h$1-IK`1zE1vZDukAwd7Cz8fzGLavxc z#Dea8Ss^I3UU{`hr2DZ#+m~HyS*IRDqM6+8p{NYUD1w_0LM`B~6n?7sSwBy(*+o)t zfmCeLxqaD|+@Ny#=dfFkY+&iyZP~gcRkb^(JJNF>Bdp6PQX|8qt+Yp%wpKAm^IC%K zK{xXi6uPy&HYX(8+T)sj-aF zRSCp%pY&H;cST*Uu$T2*iH*do^0d3>V(KsgR%Qz0WA|Op-0=if1$P8omTH>ko=h7Mk!0a_=zq zW((=$K=#}!wYi}lYG`#r1KkqH9kPkO>5w?26>mE;1^_UM5MyF_SL-Zy@#s!3@DTL5!`N z0I>D`&*ulV{D05)p7Q@a#IyYEo}E&c6|(b`%5RgY{5*aRbLmtuST}gJXQwun<4m)2 zsHvU5)McNiNzOQ;ug-g7v8MkXfj1;YJpi(NoM1M4L-+-P@!}+oDPl4y7^gX^UISW> zTwd)4Gv|I#4b8SZmR|TQH$uO(ru=h04fFp)<^O+vaJW~?|9||H|NlXrdz$~Bru~gf z`)w2Ssq8_|(yV^i`;dX7TV6cWr_FddnpYIX-|kT14T+JkxQsX;eLw6Kg_8-68d72#INlnrt_^KmEKiRo8$q>VVpX}6uDuJG zP7&MI6o$Sx5*e!Wh3R{B?xU(@EW1TL6x@q(@4MpPXYgCveM|DNliXWkye!kVgQZgq zRMTQ@44W^FY^YQ(YulSnODJq#^J$*gOzS>F%FRcK-F>XDE$B{xcU( z(>y_&Spv5CfA^nP?|(Tyd~xu!{(FeWW4~6T{j2Xw5xEc|Vr}l*i^(}jF((wK(_us? zB63-=TP!ip9Uv_$&4w%MYYR;icR##934#m_i>p+NgAZ^0dF04P=-}P3BLL+%Y=40}WC>x==+qg@fglPV73_wm;QMTXf%*$D{v|%|5h%u=^Asrj`FrBsmx2Q?13A|s zxc7s;@BYq_df$iC$)lv@r|jFn$u#)O6YNvzY%O5T93mC{*iVxBOTUn}>r=CO#TP_- zWL$NC+YA4^`>EnQkh1Q%!Z5F05zqb&czWy2@%6BKO7ry~LfG_MO$e-Ph}cc1ip!yx zJ8PB3rP%IZ-ug~*RzLV9Wnd?JfNP-eFLYdAS^ryg)2~$?_|3>P|L{FIq#02BZM`7 zP3;lcdA#MgBLazk3H5K@J_8Rz2Z=>8xy(Z=&EQ!lz@ii1*{ZKztWl*CAmOnNC*K%r zN+*LzFwU1MR=Z!;TAszThNTBX5k0fs`D_`vQhQW>oZ%q4;yixICYqT2bn{bk?WW(E zj;0Z@e-6TUtSA|!Rrdc`2rZ#}Uh_FJ{vi%J2JvBgwZhbFtnpF{uRd>KeJc8PEOi8T z-0{H?-~X^it0DH_X8AD>-jIl~Lc0r{Qeae(-NM%6@OuSJxlrjPP_;{}@{&6fYmD(4 z_lf+YJ2KJJG37P-J(p#VUv<*8miSWsi{P(CuP`g-@RviVlIUoKTt$31nm zM#u*MWkd-TJ~O9o*r$EF056d5%0vsTgZOKXCxDz{lDDfFb}9ywxA3ZXg&~oqSRB4z z65bu-h$3q8kj*a%a z@l+x<6(s<_SXDn#8;k$;94Ye84wf;|Y7TIUt(nQ9SDVNE(32A&WNeB#*mdw4udBE{M;!ZTq3%Z{w1?f`#e8tqy$* z7@$o!Z10mLq^r#UC9_ZpQXT+eS z-Qlc4hw^+Vf8?MdLfscWeI=GKo3ahO&s_Xs{@S4;S2{xeB);*-R#y1f-7h$69jmb+ zj6jp%BdfRcFSm;8n5s#|?17yk>*1ZO!%y$vx0OK#trORh3agUhx+yR3GaOez@qY9> z72L@e)Hm?;SV$9@ff}s>&J0i-e;^+oF(%x`rzHfARe1^e)W$Tgl?2%nUijcm5_f@a z3&rzAethBUc9#bDo6*g2ja{O;giulIio?D^leA*|h;{^!7X4l2g;-*gW5d0F*V1xS zH0bRR^nLy8B%(`^^4`dtViCj2pREvX5ekM)!7BJ0Ef_n`o%aXk?2n{bn`wsK@rscZL2Cr`+ z`m>dKrOR|)S5;aAnBpp8GK^cZ)zB6k7F)IyR}HP%$?nn}^A27EoWHq#QCQ8XyG6>< zv)w)<`t^Rq_~?kOiFI8Az!)|AJfBfOsFv--!_lcSkm{&t!070Iw08QGfL@`9NIl84 zv|_oKw17@uIF<}gi?i*s?BwJqAQ{HD$%R@pG!}LzGS}x^94P2kdbiSlnWyjKbo$M7 z>X+x3=E(Am7a_<`T?ms;V*jt!$JIvv6|eD*se{l;A6g1XuVP>HH~iN6ybOfr3bQK~ zq&Fw1w+Q;rSDpL5!x;Z&mzBGun4%Y^cxzJ=zR-&iMA)7#&O-S*q1NyDx)i6EbGFwJ zC*OK*rn$QXTE`q`KDVYLKBU|Ufl-|OM56|`pCd`H3{#v7jSiZOj!K-X$po=uS)kq? zF77V=ug_b(aFw|HLl3s;X~^ zRZn1;m%nE15C4zWe?hU(7B-;iQ@(2^l;{c8Fl@yzY~VP3wmL=bj+wfMhDE{zezPl1H7KO3Bf%#iB-@2(nah&qjCrR3W}-PezH-D#Bi04%rYhJ2Pd(_&B1lwakd`lPbf}d8j2H&z@mo6t6l)0ulT-eolkCxlk!bWOS4I zVd_tVXbu9K*ZCCB?|2^;zpXh-kq5xfDJa#X`eS>aGX10!fe&BfwQ&Xs5~T7A8x1aB zH=-S`3xsU)+@T4)p~^lLtGA=uaSH_s$_}mk4`U zFe5Q3-(mCdN5$-8tFXzE3;o@0gLTieNAOL`kJPw7SJv4;B1+)8URhUh16}&K#sCM9Qrto@fsfT~NhTr7on;3GvLNrn9%IMG8zyULQ zAKu(q;X_FWor~01lV55(onwL@N2jAwgc_NcOn>esULFv&=kj(|$>Th7w07uSdxX!p z(C>Jo0z0@d23vrc|MDoKb(D_%1!?gM+&{7GIfd>A6&gOru?S~km-|lv{B=m3u*y`Y zdWu#s+)7H#61g*vuAnpY273j|Q(w4>0-J=O39S>sbzP};y;ZSM0URI>MYcFOPH@%2 zLpWqG2b`UZfd@WZx)IZCz>Ys>sb3|iZFKdO{zFL^0S1Vetcra%O~&lr0X1yk-$3Im&MFG@Xc-M*{xYa+cXB##VJ1_$4{g_|T<;N^76lSc?(ySG$y&#)HJqlCSd)z6^h! z&x&Vj8o+qEWV?HC~(*xqf9qSjElje}kcT-?hgktq?edhZCZ4{!X zH!zvuUut|P_E!s8xivG`)q!E!`84NbDcfAZZtj1hy>A->HfospW5@_XH8dUKv`(Qc z*IRDp^d-s`k({cV^p}^V^MA*8cQ+T($*uthab%CZvQVS1`$y~=fG@c>LUpS^=-E7> z*FeHUZ>SlPlgLtdC$LnQ@0@08h;w|(H_e4 z1`+GQEG4r+NQbNDD~8)}h^S_a6|I?$A^$&Ax9$H>-GX{X?U7ZcoFP&On8j`#SiYGP zB9b!MQmQq5)vH6sg9bOhTRlx&ByK=6sa*oLvYd0{JUn-L1BDj(w#<6AF7#Efi+GA# z?TVN1GjCrKNfXOmZ$fmDn8J5$D92D@h$~*aKw+j-XqiP=`e=69AjZr>%7Z9&lV2)A zhV(%Oq=RWB<(-vX97ummi^wCVoLt`V%VC0)!g;s2g`}xcsIP+jVkOrlTyA96R=QbZ zb9!0;a(A9SIXF0&@z&G@F@u9h;D9p6_xrIV2Ev8^2aU%bn%Y#L_>c6H=gm)xeR zUlCjSJ#;P$KT_q!1imgWYTcL2FD051Ifq@73?Xd^3Y| zEPm|9wLd6m`5v5S^(zYlh2>_%AvD-z^DRDKDOZE^Rn3gs@TP99od}de{kqcOV0Doh zAi;3l8n@0O71)roxxuc{|G^C497jI+fGhundyaSy1m1K9gE?{YV_!!Zo(O@r>(Pc2 z6k7b{3dx2Wc%RY9A(DtlL1s|l0Qm^xr_yLOIs1YG|z67ESM#j|MMMH6F z@py~s!yyKr`Qa+xq+cagh;4K?I~HaUcPGr7>71JW?+E`JHCU(@u;r7EA@m1SOg0c! ze~>)mo^F?IEN%?DoEpkm5d%meQ<-USBh<&W^K`#ujYWY{D?D3td@%DB(t-HxT^XY4(9!1x5d|6sk3- z{5dx@5JVWt=m&9$6Upw^y)9(z%s8L3Tx44Iy+82YfVQ_Y_DNSH2OIHMiDW#?y586)wOvJTzw66RoY5sCd!JPg65#%e1T}t zRIO0GQrkFXXe-uNt>L^e^%)XQ;e0|)={ROxwD^t_+4)p0W}zB}gkR56IUTfF{P3Z- z;mO`!yjWXw;fB=n5}a*c+{Ra2;+IUCgQkvC*_>bR+BrdMd-Z7J;@>11vWhk4UELv? z8|=mdtYa&o9B`%iaJE$bQmMSz1N*Oc!yodUK0@qo=hTk+36R4oSq|qL_^^n)Dd(wF zUIB~W-5aT>!S*>8ld<=fkd#iAfK9AW8%}tAg>W$V|Dkbp@)r~>!>AqQo|y$ON|?es z6AL}50T4=C^{hnnGLi>fye@J!cM#=(9W+++plRvcp#dA#{?LT8iVd6N(EMdVgae}1 z8Sl&*JPg!~MD#5X(f+ujxE^l^pK~-P=4L@@n=0shdKu2T;z7v{NQr*DL^kn=-Ly^H zxFa3X9PZVzHf7Z}{28qLKO%A!R(9UUd-69j7%{zp)4vokJn96|NvJ&r+G6bKMUS%1 zCx!C*5X!vu6B%qwe=Djf;m#Kt7AOiBI{Zz;_cHtb%4~)|ePL)TFbZkd?dVzxcMnR? z-BJ##c`bqiH%m`HiwK*y%3B`K`NGTZnDK6;+99dmpH+nNCUipPf)s0sG`nEcY{~aj zo}D6kILc{VE9b_)d1@*ozt$7sOom7lGuHhUzHw?kOwEI$h(UVIMxx$}im*GE=yd{? za*oApry~Lp7i4BKHdVista@X*njy8ZWMJ4-BpJpTgdt3YDSaZ4N11YmRa;^=O^m&Lm%IG)E*nX-&-CbR*R=q9_thjX0hV`f;*$)uoDH_mp#LQ|f|veCB&lITYYs#65_oE{nQS;bkx z+Qi^FIyASg{|r*&4x}S@{4b_#t<6Z|TA*uhli9)k_u)6BY(6H(KRI}Wa9!ohlaD6W`D<%iLqk>BL??=sOs!% z15OaGhiirL$k}u+VbG6KnLOyEb(0nf$1pdb^mxQl_*HN<707iVCpiSGZX$g)!4R*% zxn{U+lQHC6(Oz7eX#67cq_T5DFzpCxcNO(Tc*utkV+Z{vEPLA-9N+Y^qbwA~AuzR_ zt?em>ynT14y#Kn6I5uXzb8N$m3X&$o=b+`ZoCWpw3&A&tfdi`mYw|LUnMs)v?THG# z{F1AB!RuU_zW#2HjZ7k->MZ)Pt+`_Lcrt;khfv$e|LHIpn{wTLMeIs}1YMvoUtgFY zX0A+e9vdD*KmI%MJwDXPhz3Bty+>Bc%r*u zSAluvaHw~rcuQN@jE%1vW-@c6VB{R>SA@Egn6@JJ%OoehP-|+@HKDW_n+>FSxO1TtOIjE4G>?WTBRjR;V%xS+gD_+fae)J%BsKyZfpLHGDN^-9F-j%0>* z!lR;060^{aKkyKs+jS72FLDMcWAna zW4v$*kYQUPI&tm-VY_I!3Dl$UBznQGv&kd>P*MYO#w*J z<*uxCMT}^1RT}ay4*qW^79*Tg(OaR{@GL|)4MJ1pXaqxZ01DdncZ2Ny%5XuJO?e2y zxSH~`)P4>>7*(uKvbDK7zL4J1pG%7v{X*(8+IM~_A}^eaQ{lhH3G!G_ZyB$j*nR!> zW1O4+Nw@HRL85f0@XpTW{S&lmIMuG=BaH;Qa(9d{0WBFHcmCjimf#QA^StiWfi_to#z z_RwD2`!N+ZM8M`ARN6EXpEZ^6y6Is&!>iMMcyyPAGHC8QIJiBTI6D27P_|QXHazw0 z6F^}jGr7!8X1TAFLXf$TF8knZbMNa`u=u$-d=55v2v6a(w+cBxnV2U`--GiY?D82f z_WhI3g*K7@XtNBkm4u=iQ$h-I`_C(|vJPrMmGa)_1Y{UQbiq&mzzQYW)JmRv$jcf=Px3+hWm_-!(|@|6B9xajJWN zd&IL_Z`EW*+g7mZgHq*bZ@bhIe>3!0z9_ey$OU5OBAPPRcP{(xBGdOO6wzm-U%+Yx z;&IBKw70qodO9;dw_WJ+_tAF+?0M$6KK;lj8d&$yMaEk|mCz_Otkljs4C;!!_7?>VuP-Os%_VpZ~yab{Q zMjoO#&FN`(n{c$B#xHaG6W$u_Ij>L7yLb!BmQLW(l$=Z==Cq`xeWyRd{vhD3g9NjX z1WMw7%79d?Am5JRWIEZ;Go)M3S*zp*`Y!&SqX1;#WBy>2KKb<-Fe;b$Yq0=1A8$c3@$h{F3OzMi`qI zU5p}gbo=pYQ%W%v9Xx*)B$XDMPP~M|3B0>VufIJ_n?EGoZ5KW-5dm16HFV{8M_a?E zc{{B6Rh47Aao>_a!I|V)f$e(P|1bbR9NRhN;X~9$^zFxTy$yf-j)*v>B)VqRbUA=< zi)#PdCiV1n7VWEo(ZvfSZR=b)gf_K7xK7i1GM~Yadt(9TdX9Tw$TCvcoQICL`td(5 z)>2B%X^T{<5sUZv&&|3S4ScrlP=KJ5X8aO>bJJeZKz4}Hh*zS7=-+?#Mz*kF1z1+F}6>6!WFln6CI zNA>cD&+`|k4Fc>QEJ7Uj($d$}Uwa>wO3->!yEBRMaDk{Wlb9aG^t&UbdNlGJ`2;Bj z?ZEKjawHhYPcC1Ko5xmM|l* zCiKMo`eq|Rw{WwK5!oHpulo&(*MIjD)OlUB%KRXZvs19Mzgal$gfH*>xumr&p^-Zm zBMNUw<10>i2akt{Cf=>0Uegh3{Ie&-(|S!7%C-GVX$u(Pk4GXkVK& zaN-f&;8A=Zw~S$NtASwu;oLaq4TfR2x?+EWZWP>xy2a$}1-2@&UMe+e5tXH1vIS*H zj_IIIV1%Kv0f?UJ`<$62af5o~lm{@wakXWMT^pA3OQqXyW%K=5vf1qoY-fhFI2H@z zZWg?jElp<HNLX<>`q?u%EVG0JlS%z=`Zk1 zA|ldaY3Tgx4}bI5(&=d0e$#`NKJM}Cv8jb}8W#`Ib%byo*EU_AH zdZ9pgaewP^?qQ@^y@mBFb6n;R-AM{j$Q@+DxRg}f4=ru_M*#^Ch%@|KpL8IdGt!@I zc~5{2P&(3kyC$4D(t68(AOH9PS!4OILRPfr)?<#v;3?Q!oPPlO*&=mwg16Q}vcx@!j@^DAjC^`#r1WmyUl}pkvt=-*bN!70@5uJ~f2n zjo9yNC-kY?4CHhb8ZZI2OL7ssJdQU7S?^8Ct8#0_1{PGS`e^k4X7xkV(nAcLzwi>I z@3io!_!Q*`21MUen9#lyL_y>f-7zvmDwPSu?J86XzyacxH&1AN4Kk;JC9n<;mS4r_ z)9ek=7k#jMXNCr%?>=8NO#{;L++Q?J57Kd7C8FD?T`=!3)0oykX|%MxnnZw`A%RgM2@K* zuLT7+%kNPa(t4(Z0pCV+^m$d=XDOK84HlCdmIRAFL@k)U}yza7~c4YrZ3~_Ues$LD)farHB@P{$Q z_qfOyOWUg~44ujCl7<*@Sejo0ekj6{xYJ+ZT73*-3G25d4M}aB(6}Y3@|l4*rEjo$ zRZX%HvsGnkJ$h(oU7E0FPUy6je0lxCxs3Hy^%S5EP#=JQ94o~b5LAqNx;PhHnQr>)%>IVyBE5#+gg{%ey)y^&fx zzXpTbO#CHUPz$d{w~uTpTj;z}F#KK#x0zvz7^cVFXa7=Lkm0Al*nl+f#0M6(E-^|{GZg#@N*Q*;rbuBp<*gRI!t*lneNZJ1xT;@J@<$aV zdE-e{kAogpJ~daZNz31v5GU5K?!*FgG#8HJ{)}5Ma*}w6X$RCG5B4#J1$AuW(+TdM zb|bI;1Bbstmur{Ty>Cj5RB*yO?j_99!o0c6W7Y?PKEeWAEClXyht9;l859Y;_wpYz&30|(W)}gmvqCAHM6ul;V+7&SqeRJ3T%uRX6=pq`Aa7Wo)fO;`)BRP zcDMxN5ZNJF>E9TQyS`bN1Y`Z5^E@i19l*mgl9HaA_d{|Mb(R`!7J9nhQM3AwW2K$i z){3j#3|k4MirqM^=m}=H5}B4Q0)%gD$-95r)=t>kxe0qPX%?%f(aH6qp~Fw9rE%F$ zLfaNQ)?75Phr#)X3Zj+qY+CNhwq@Eu66B9`?EUSu)hY*zM%pN6N`Y*06iCY(XH6p4 zUW1O?S6W=_H+~z25Fjo)5M_1+>A5LT1Cp>|gWC?m6f(sbR(Q^peS1s`aivIFpjPXz zGAMv7g5J`m-2<7ocr; zJ53=Aboi)^7bvTbTutHSuG{#>C7vhaVlLlq(;-)_K(ZRF!~a=0zKk`z>IL37H(hIv zSR~QCHpM{G9W;z*ELhm#KDMHAIxPm0OHFVcHC;SF?sXCUXxWF1g4OtuBiaV)HB+@PmRJ_5+{e01A4)K zZi%>XJxTolS){PY@SI*{!#T@MmFvhnj9@eG9^DD%0iP&&h%9mm$HU>wW(3-vwM2|c>I0L=%3}uq%3}Q zD^V}I_&0l)q|l0`ruhZ-G4Q%&Z(ZMf+0_q9DC8bxw|n$PYmQUx{GUT3NR(3a3BP3_ zhv-%Ke}5^!-^vm4X%0rC;9r;w9;A-rFqj_9#Mz5l*_4jlr^6}|Fq?I9P!$paLc2@V zJ0Vwzu_cKO7fnomwY6^#8FTzgb&}|F@1&6*<2aUNH6kTU_%Z5G_Kyv!vWor?+GPHe zJSwBHwask6XmGXqkf3>WceYF-TMz)=@yvbaHMDrFxW7DH%1QL%s>8ma$+`HiG;cW| z7?sl$1x_cvU}h!mf%oNo1B`fP-`F{lg$-}eqUMvb5)LZDW^k8ZuACLcO3?zX7z{yK zoLfRRF$`$(+Hpzzbav2_J6HX;3QOE77y~2H0lluxYyG0^$!zAU# zs%)WrURP{d66G9KNKGT!KhYkS2K1VXF|(3~S<Z^sIyKqt|{RVHk<2Ldx|)AewO}H$mP9?3=v%xKdi=0se^=*iee4d6oYI3 zF%&EFQ-9{LHe^~iTN7_tpZg9(SPZH{ueHSq^M)(8Y)P6IneAA-IuTZZJ}@I%u(S^q zBw^spf3N&~<;ppW^1OZp@6L^%;9qdYs&bpbb@+8ja>Mqo`!=nAexp=EKV&G|_7KCe zji}v1rfAlXDe}Xun!q;>tWe~s=q00$eRH>>un|UPFn^68kUM&GMwc8WPv?m|AHQ#1 z=JgsN(@M<|K)A;1us4K!f}xn_36HNnb;ZQQfNGfDfI0(`#=GdICq8yjLPF=Qd7n#= z&tNsqWyfxD2O(7~v?^s3I zJF5*>&~wmOgi<3c(I-U1RrH$L+vgWtI7Ch&^^EI2fj66zg@ zfoC~GYRdt%nY)f_{7E}>>5tqMkH$eFVE~BXv)@+h;{;8d+ieqM1%LA7h`VRM86M6T zx#sfwxJiFel!C;T#MR8cY@h9~*qC=%`_b7x!+5a*+Lsh_u5912H6a`a#KZZq8nVE3#Ft`O7o?xXh+YQenjn`!fL|_ zyXSUnl|v^Q_8SAowFG^xX9XJvbzlWZvZT26k>%PjhO3GT&Kxj-$Rl$6;9x5}$$?`< zDd1S%f^-NDG5_H#t4Voff#JCsFDJd*vu}s3IH%Q9FvopqZNGjt8l_w1cLmjFp7Zap zxn78L9*z%}{&?a#dWKX(d*4STb~w$v(`|~9`@t)Z{&>V{`G76!7&H`adB_|ye&OIw zSv76KI#H2guw{$xr{wzJ>(zjjzS!UG_)NK}hy&oC%P?11TW&<`Yx5fhzJW=E3h2bE z?}mI-D0{Z4*+CqXQQ(-M?emOeee3|0@W;pI8-gAm764!A({`3@$ePCqKknv6?pCP$xT8$7m;?9d$| z(Pu6gt+d_W19gDzW0I%Myrh4&HJHeTS%4|!K8N0e;mpqD7G!}N4k1D%>EtQ_MW3HF z9*taX4OU9{O=&*jE0I#X4R^L7IlABGU8w6sEd@Lr_ zd;1O<^Ce?O`42OH8%^ru^mC26mF_?#>s?j7;l6+qwWmh`UrpgJQN60Qj&a)>1 zo`Vz!FEu< zH^ZaeT(hM5h(qd*LRZL}{IThRi16YoU0}wOj5Oj(RN@)Q*$olDq{elul9zZ1rct`0 zxBZR_Nn5hEo9$#f>fruQJ6EX;uA-inG%V?^c>%c+QP!2jg=I{qK;tcHFtDto7!xim z?bIbr{Q5!M`B=Ds5DZ8fZ^Me$46>v;lRP->L)@q!ii-10mx}I9$#Y!1iq@302ljU< zaxhoJcBsCtL)wkQM1_HNNs{`Te)V}#{a(DOnu6VwqV|j7DF-~ZTMrBlwUG5#RJJ2TA~K$C`RD5xFMbGmSRlLFBRwuB14PXFd%m9OM2!7 z_zutCXWH0G2i~OlFaWpQCjyQap(}JMu$&lScm<+lhX07%=-}@=SZs8c{YjFfh$ivRDoF+#Myae-qOUtjmy? zsmJJUlP6(@;G$fFfOj2jfsaPq&r%#HU35wozMIueeQ}O#Wdd8!X;Y+26)Gv+ zU(LP|Y3-{TYIJ_KcjiOeOdP9|XyFa)f!^Bl9fi#icXPOslpJDLDAi6&%NR@AV{ep$ zTv?BD-RgQx2{uA8sphCks>d4Vi(%hd@?caJ5I>$SWkfN) zEA+9yTE%jnpkrzYsol}4YxA@)Bmv}LmGqu4n7|ys!r;U?ITJH_B&5(6TIAp&92bDC z(2&BAo(V+Ot>@VHV}`>qHyW_NJX~i;q%gwI9my(WvI3Tv#-;xvJMk(K(W0_-&oq0R zrz0S@?TdSEvD8~D*$WM?))?G@rGKn)B#|1kX4!To^;g*cf#wacyHF%>sZfplu|^>) z&pfQK6p8rQXknl+x|My!;e!$siju|8KcU~hOEB5vC5;Z}B$2{)5Qbya&hx`zMejdF?62&XXhat z$GmFhLs|x&cJG#z^+Yru6em#}b=$BwKKe61lrAF@l)52Po6#%Km@u}%i*an{Lm+T= zY!CJmfxACfa<4tugl)QL+0eiVrLX`mJX+YHu&y9mV~ z*!FIsx)ZMHZi_{Tj($6r^5n!`BBWCudywm?x4w%?hvio^Ex3SoCDzENa!)*AHnzg= zrFR1?^jkV!=(|LMoFF)3`2%JX5*#%NsMulM{*vH7;)(4}gia_Sj45@ZCn-@G4a!wQ zTAdPK^pV~_*^C+o2T*cvxu1tkB5_Ay3XmQW|-KyKEFS()q=d%u{v2mt2O5k zRNX#!B+(9sydO21nO~TR}q23pY?JxQ-4nIaX}+=I^ZhOu(QZxWjAdi+$hQa6|G^Quox_+9phE;9E)h> zZ0o5~QbqG;Dces8fmIV#M9!=hffWsI=MfYD65!F+>*$pPz*>_ap!;g!d`Z_50~_CO zAmgq5wtdF@{D13OMD@?HPgZR$y-OD^)!@V&3+_H{s%&pIapq?wlHooCHqEIV8HLif zak+D09V1fB9X6V$+SXyylIRF8pzbj}B95s+ZM(jp#Y(~VX@aLut)k3STSJ)F1Yc$M z8*2zgFpP^^fkMwEQjXyFO=H_ruMqbcl+=U)^gwidAD33O6FTljLDkMi#s3l?fvO37 z6tl|xR0n~1F^-_5=wHyfHxZ>oalx%6 z8<#=9xJISv5sw95bpXo4WXSA=K?@ugN@|4GY;1I-+~^D3Gc z#ROFkH_5QwX5z+;2nrA2NWKGkL=Wa(cl^k>v$eYh&0Y=|{yPu3G1?6~W%P)#%dg-F zjCJM9FyJgQRuj;Xf1);V6e^0HCmspibM-JPh_Q%G8C|eQbMJM#H_C@jr#PYSve>Bn zid$*nAqr@Q*=*`nSwE*A_rwlih`VpzF#0mU)jsAJwYSJ9z;S;bm%Q6`{jF6&=^s|~ zvPpROX%)u@HQ;PFHSarBl&6R~`e@F!C}K1shVn>`r)ahLUe&u|>df>$L{yey1x?XU z)AW^)(mKmFkN7HyEeuLBC=8Fnl|=d?xH@xB(Dkaxd(w5@mG2HX;J0twb(b+c5N|;5 z&qnK}3!Tv5Abcn%uDP!@=gRVsyYqVfItnDp%OUFh8Xf(9hZvt*o^f4C|6=y`#~3POPYA-4g?%8|F`haGcpAkV>2r@axN_G5E$=pwNa>wn8nYO6_`|KvQP0%w$D($OJcrbL99cN zvYr-f$_4CN6OdL_LO62|kIBxp<6C8(J+q0I0G5FR*)cg|G8Wx7~r6h;u}e)bq;g!`8YeSw2o#_JwS#FtZ_y92rb?JikFM9S%kXg5O@AiA6ZIHrz{ zjyGoqqqjTV-QD+r@4iaCKsDf9f67g-(5cY2??+kpSIXDdf>2WTG<@&B%*xaWp(}mg zYF3w>v4i4bYX$?oeln7ih{LvefDikgWEWxbT8~r;`Mc}R&dW~dDJ`#V z6efi7qF$YsD-{0jKo8F?5b>XtGap^9+It++Doz7YagHA0wrNE1Hw_}%eu zP4Sr{7s~Wsk~?gsrsQ9J-a+p(=%On<3{_8#jTec zf3(E&gPhyq1~|t@R8I9n)I2-|PO-+WvsL)ZAP1 zLlXj*GukAFCMv#34{SWmWAW&`SmNyAONF$~Yt2{oaKYzm^xZtS0J;Bc&#C5#v%I-i zjrStK<|Y3=%o|!KK}(+GR%mzcdG>e|iPwu>)+A(;XI#|eu{_f=;@PfEdlJsjxLEeT z#QGgrb<$Q-+^Ic#zKT6Qf=1~Ele#gcs>f(UbRUjK1L1dda#GZyS0y{hzkEbTXuDrf z>JAFq17$Ew&Vl5456Dj@&3D?=(p_itVrUTEXgV8okPClC1yGD-E}>15BQu7rM_dxe zADavS*jax`1SLQI9dWt4EeMRzyr+7Mg)XzZ^)(iIC4x#K<{hD5A`1m3wbXzd`+<2~ zC(_!iw*xlst)FF``&3r8t!&$=^-7M~&e3ecE1jO%1&X(a*+LM(-e%M@Nm?T2r?Rt)1iL zZA1NZyYAcC-b)+Itt`3Prw}>>@1hv{{`>XSi4Fn=IH~oZD{@xcCYkNVk7#;rxTIinTUwE26%#|FZonVs#dVClDz6@X7!$jy7N${JyLC@SbkY4 z)iAgzBj~YhD^!TvW?V?6WKXNy2n&7oJ64xA@Js(Ve4T}O0t z0$RaL|IPXROqo1Q%_4?G3<}-?^hibl`m5j2?*?YVNEp@y^CxF>Pa*d81$m&-L8_Ea zC^)chXOKOvP@<-jMSYt?3p!KOPaB)2PI2w^VDdL2iB4jZBb>B#eVfZ@_>ji93-$uzE;jYp4KD%F_srW{xc z>%pN+=a22#`@Qbpe%*QW{{Q{*>!UAU9(2fdfjs0hNyQmdbs*-{LiYpgvxwX7+E?~J z@mb>k#hO*ui2eK1^7y}l{^Ncr{`dQXr}z0ExAL^}|ALr5A4@SEjZyNHtA1hTHl9i5 z)s0N>6Qm+S@hvUD1`ONzp7)EQBX)>~wlf;>5R`$JdVsw>a`>!rvXnPcCbG)c14qn< zF0&Iic!#IZ2~Ed-Dtrso-d=}vu(VM2kJk_k(}C(8@Ci2U?(KE*{kZ~R|E3`9uK-~` zgRlaMS-iIDKsGH^NL;kC)5w|`sghu)c)+i9f>Rqeo~2(y`n#zrTpo>diP;Le#D3|M zR~*ZE<*iK_AbZWe1f647Z$5ax39=qf$(4v7rX(Fpab-72J+6V0bfJVb{wp8vghE2J zY1FJBE+c7v!dWI21R?w;cnm=cRVujWw=@oGzPB2qZ?2#6kJT?GRoFd$cmOaOnjStQ zoe!~1kUt|YPfy>R;#DB99!>cyTO3mY74r34TI5bPvEOMP^qEm53qN)~R4)U}i`}ys zi_MKNlDQS;c8Q3>LLom>rXNc(nd>>{_SZ|3$y+J?OM-~blhToE^tv9O`cMZGy?{Mfm~E(B70G7}Uo^%gIRDne<&cJa#8m2n z;~@NubpCf~cX4rkR?|@p*6!doNbx(>`%dZqbxN3(=f{DjF!oYMp<&qk;oHe9LWE>8N zc+u6+A-+pLd-|~RwJft+N9QYAtaqsYEz|!^9LKc`fMxpsJ#`03hr$SN#f~b zz~qiC7H8|JljAhI!XlM4R@ucMd5K22*Ehd-F>`m?vgia0^z%4nBUW*BzR-ko{ha6K zS~C6G9zxpXo^AXhZgzlHCMUCgoYVKiXG>1P>tfJq55$Ee+wAv3=XKFaJJnXrp+z`= zGxI30T~^57<4ttVdzjhs@ws^iN#{)+;w5;8u9>Ho+OZ-XoXSpR4BfQSpZn4c(9)!` z9r8FW_O_G18%BbrPal`x+u?v!s{?-4ELO9pEshL0!H|Mf>J8gO2532;mAmtK!mwUC zT;pu7&}<}m9g>7|3a?J}0Fe&#URc1?uLUssNhsf5Ttt;@y18c3Y=qAUz*&m*c7 zNSkZX^SIR8igc}hzBmABb@JXgbu;1yOs3rljp+zZB+P-9Q!Edp=lQEMxM!P%p8f!? z+lGt#rM(^kX2}r7{oFfc!@RPaJ6d)d7~J>TGequfWfR(UyIDTDy6>N{YrPFHmF8BN z(^G>t&dO;A@x_+cf>G@$C5oysRX?#gDRkW_6T)0gh({q(i}_ZcEoolNhD{^YrNM-C zc3koHpAw9+ME^Hg$~Wr&@Av!r75{&K?_U4Ejb{b_zoW~SZlq`w2ZnuYbCdzqg!D|u zDGM>UGt77PB74;Y-lW$23A{JoRL8UTT%(#}kJGK9R&9@>CF~C7#V<_IZN2Z!B*L4k z??r5qetfuXTA6wQZvH=Bt2zscEtb)?P(a|iXS;tBG~z?94U;4RWPR@)!``8Ns>jff zt1JW^ZclY~^4w}fv&FeZ8g59~Hl%v-`b@V4Pguf&9p5`17H^iwg6tjI^W4D&bcZl{ z4ZMMNG0k{kHT8Zh_mmsA zKH^*ele<`)K^Lr;g{?NQY%=l`hibcY%5ks7B~<(N+Doan*G(^}qwKyvmwQ#BcMA-2 z7D%3uVM^O%8l}9OH*)S2GWXXEAo|o^ps;*XhJI>xW*2W9%N2O=%k_6@+PINHnwE(; zcEf=ms+>e^w~snJOVeHPLY6lmf2XO9)49L15-ILl^@C@L{*TEAH+uftf4YBA(f^+u z-1~oS}ZM&c!x*O9iQ_n#1Fa_&e~)p#I7_A0YS(kB8zq7vpSM>~UP6 zX=OUx9G;wxc#DL&3NM=Lo&Ad8J)+87hg_nl(vsh;jdRnd*+mYmC@{;ng~FM2rgha2 zsL=JZ^8RBKo$7ZhZmnID5MAc_T(^RVr^>l=ezJz&$F7EDVfO1anyTv8*wh6yr+`Jj zUR5Ydol7=vC3G&GQlRU|9IVoL$sp{wb1ztKL$F-3d3`$IYscTD8(Db)pDthCmwAQs zF4m$we1--73(K}<)f7waR@P1Ni(>F$wMRYT&ooJFFuW5VsbP6WcpS1%i@ti00o@$p zxOB1EE|#ygEP+!Hf|(5^zVt2LR6YmjtI zwqp3UST(ntKijX#son4FkWR$nQ9ACB{vOPs&~pee1VszJ@b87eV`k}BIF@t^Ec*~= z@?ln0h+K`CG?yb=8goV9YV6Qov=&M|*DMCSzQiRI=|Vp3|H97xtJqsvDA_DO8~t4) zly(X8M~7MkQ@=+Ug*!fZ$D@cOJh&u7E>-GWnU4X1W_^a(8G?#)Lb?!NluJtuGrlpH zjtp;xMAA4ElZ$cvy&E&g*i3~sEQy*=1_ICKT6CRzFKX1B(tMy3 z2LvO zZ(nZ?xPY@=sKTWvptg^Pgx0XI9t$om&M#<%ZQSynrS3yzzRbD7I`lGF@mztXHN)h! zTY%Y%*M)18vLs;g@RH3J4wKsAD9G6`XIz!{;e1J2e<6~Rg*zT0`#w3z^4cw`GfvBk zBqyF0nE7&57HCVJ;#yq@Kg4~)0?n2zbwz-yIB1fNsrg{acFTA(vqm$bnufJVANb@H zmPRypR!fOo2IC{V(H~b*m7-?)%(6F^0^{Z5Kn{HIupm1SpnPDwG2DW;bo;MvJK4tg zAcO4i8R>LLmgHyFX6ff#6qGL^$X?i{wqqm3oc8@a;v4j{#)bzhXZ?gKN_iihraV&q zh^0TV`Hxaev{ZMmUs4_7mqfp_f#t?Z)39%CJ^#jmp@kmWt+Wr@bS(}GN5|=TK~oC0 zRwTsbG$Eat-oCA--oojY^=syP#}9Rvxyj=W zwAH<8$}pVgYWIiEcj`ljgo0t+Dod-4)^Tb)U<$5ahoM=@{OFmml z1<2U3V00XaYM9r}A1i|bMG@Aj2vfzXTb-M?HRVLGOiMi=j`gysvM|lC)UNYlu9a^z zw9@3Cr82{0I}%q+l5M?r97V~PlK##P{`q=3VUh==zeBdCNm6a~+0<6~*lAk7&|U?c zS7dY32W-SXo#NsBQ53!6Dfp~9A3nTuXaOnFpS3clQc0e)?L4>0z$P=4$XgT^oElGu z!-&-`y?UWjL0l8+^>k7JZ$X#!0saM3GI1HUE~t8{m~u3ap%jx+R*hbayF_U9{E91x zn^uIUrgjvnICkeWWnLvkcX(}{-Wq5JtmGT};@bSxuA{UYISN9%Ds zy--BT8Ev~k-`R0@8zfYtvQu&TmOd-ev`%TL^9vV5%B(=H`V^QeW6o2ONH*hQs;X8A zb1;7Xg zKThX<;bpg4m#KWBW6F0_K6CFdEROhW@ka{}NkMK_zcR13+3#==TxhaWI$E-utJ?;X zo*i7zI^}R-uL(Q|8C`3 zN&d$nli7&^9@u2ZGnQ!<1ya|P^dZHXJ~dlGz46_&3si?FN$|=U{w#Nf=8`W>BKyWI z|5SH-p!>Q~_wo`bWqA4d;LD?eCTKzy16BKX2z*Vf|w<4<6%v z8IVe!3Nq5RwzYhXPp4S|AU_%R)QF{K-7hw|ZP9b{D}2+nKem($4FfwKB59-k>S2cQ z&c(}k_LfR}nKAp62$`B&t+9hIU!FbKzMKwNkVZfp>lARp_7|q&mW*k~F>8vl7&Dr5 z1^G>hSj)<1oj<_;FCFrk45(sHACoRrr!4zZewgwoBrKkh8I^dVj`3y` z({PqfWQiy^i*{xv^KRxBTs}3Wt{mqQyn&d=B;w$pQ2HNGB3`S%24Uw5I3ajW75lOB zDI7F(%SG+VW4L=pV{dsKyQUV~1kWmbvQwiU!=L%FMPn}wp;~Fa6N6jb?43A+OJ{E3 zS#B0Rg@3KI#3~)<4knF_IoWn*(C-v|i}lW0*pJdTgWuq~`O?W^*38UiHc};o&*`UI zb4HtB7LH^y&M+~D#VMD@J1&Og;dknxaVZiW6MKF8gT;rjB`@i=b+6{Y6gk9s@vO-s zT5z1s^!(-F2>1!~NEWzJ(Lrx%=mdfkT=Yap)6zIEVF^J5U_@dOcTMXyEY}>jPzvR{ zWb=NJ4spU>2&3X58+=Pd{$$+|K#am2MYtgJ34)R{Q4h<K)?S7nnTgA=F;E%QnZHAI4YW9} zjVP_lPVuwklzb$cHcM6ht&p0mK6!y=-XY@KxJR}nu48nT(%))Kn7jwmWhJq)(4PtS zZPgLBE%gu%eo;)GNH*l3T6J^D=01K@>d8h2yK%$0F_g!zmBuWFu!344Bq|OM%DI0~ zfx4VU3TLc4_N5^R7Nsp_3s$0dRoPp$N(6KT-Nx|e8s_aR11xuZRo~UeGUo>{%Vhx6 zI7uq^W!ipg!lm8#$jiq20JZgRpqQf!eu>ZVITwCQlTkGI1MItQfvUNwBns~Evb5vHFdn?`QC%ye- z*nV2fg6kV>o)L@K0@@dxj9T(Fq;=G}xUWlh8`g~Ty%Npct-xv!nXX{Uf`9d^&qZR% zoR?Qw-EbaiPXUDi1o3DnXD_MN@d($1ArsK7ZzEWTHCLfi-n5QgAr?U1G ztqhRUyxh|?9XFefrGE5At3PNk8&8Eu8%#&(yy_H2t?5T^zc$Ro>0@esUi$rV^L6p} zr!0wh04&mkPPIj~*RRwhF3(bFO!ouytI3pok3s=`zYX$@mq9tFw@c zfsyWAhy@sSssZksc0yQ6SBbn)H$*w!-bEiT5ObwZ$5{)V1w?3ARL$I1)4l~0=3m_a znd)F#OtJqIM^2j^aAUrl4Jrd|;9kR-W4o>CZyiTY%WgL8#<57OFz;)+aGH9#rUS=z z`<1(ITyeU}8Y?JuH|V^%!R1y!;X3Qg-H}#VSPkE8*fFQq?+P=UtJ&Y=tmfb^nNe3t z*3Fpv``xE2UAO0-a=vxyy5R}#Kk+SAcA9ly+Z#px&Giv~9o{QR<+%~tW3xKJ#y zMQ_0Sg+2%ugs;*qW<=e8fLjbda2MHiM$P(J?u>)tO+}PTu-v>)uC$|lRX#bz(iSec zTr4ef#+jBam>%1A6-&EWS@{im;0z%5zPGl@#^!u)pnMHBVm7vbdmW#E>Gs?9y%{7{ znD=#kZwJnXKl6<>UbA7+4 zowA$vi{7OqdY0ZeQ0x)aGd%3;bM|<5zdsQubSkeChPOZC+ z^(situga@*$B|yhfcJ4;cjIeXy60`q)3m9Le>u$SSXj{Mx9wvB6k5;ry8flwKCbIs zf=<73-%@KQMziX6lP-*#Szg!nT;RI;#^br_)#z_-Hru-hGimsB$8oLutlJV7~3&F-MQ&Gmdj&R93&7^)}m zO5P!-i))sFsp+ZKMU+{WS$o&~THdRc_V!nmJ35w(;n+$GqKoQBt97jS#m(jpy(!gZ zwUli(^Q+C9?b@2Pv7r((RVa$?6+#5Hn3wX$~`{$SjOz(*1vLFNJqCKz5Y*WR2d&5zo2=^tMcg3)4-!0nL z8ZLsbzrIYA?*~=Szu2$ zjp86!baYM6l{;BqxBJREJ1Q#Sic`>_R^Fg9WV7Z$Ym9D0dgM)i z$qq!9OAyeNt4nhM-x7C?B^8yic&Ag{N7a^bBWqW7q52VTK$5u1>UyH2sP2BlTwIIK z=A@fT=oKYhxz{CKZCKv9qb2K$yjt7#8)lbAoR+Xm14|^OW$yCBqIP%VKVHHAD_O|b zx(H%P{NK}qy}fe$-{brHA8+UJ)^PxzYEHPB^j~DMug3Qa;555^;q~=AzBt0oID0F^ zZ0DB6&)Rup8w2hNom{fH@)KxV>Ikl!ppyTag>RWu4KBJuXU-@748Q5%{M%* za!$7M;5WDfsf0(TE{I}h=~vYc*zdKdS=V5byS-7bZW9Mqb{5x1fmMS9L#|xs<4UB; zT!_nwg#Ll@bn|<3w5!^WN%5ie;=-B_l`2Oi`5T4Y#QEOv6{V?EXKRGpT6~H1^eIK*jDlaEV2I|KRqbh|NGzf z_wMcg+j!P7|BX4U+kl}zU{zZmb$4hF3;Vfu13XMn&rG z?HM(>VYL2cN9$*!wNd$+G(EiMxRy3`C{*t}E=>bToXy^1S?}aHADeruQ(-j`fI1$T zu6XQdDE^#IqC&P~ZtOMqQ*yPU(VtR3t|B8AGf7hx_S&aenrq*ejgQR?ZU&f;rnG*D z=D3FzdVRiC;T6$-<{c{-Ov|}P@px1*7jhoHo8Ts#)C2 zI~vg7a+-kcqr6AHx=Or9{(xS3kNk9!c#r-+Z;QO8l8dP#$1h$g&rhWIjRmRa^N`UV zwv*yF&!4G4gsk@sc_r%B|LM!47eBxBC*g+1SiJt9_V*9^rS<>#@ss=dKezI1kso*( z(+Rh$;T0c9t+hPYEa7=a-IQJ6Lr|@>7Bw?<6bBN)k{Uf1J#SL=|{s< zTe{5-_`gR|OcO0qkkLpaMm!(`mR>O}a10>$o$q;DTjc!J-(Q@1-o?d*)~vmdB`gkE z9B^i|cfGeBn*Ly)H?Gt}()U04pKR2PP&^fKen>3fW)L%`ABaiM{96wOBMzt5?r|MnNJiya*J`~Kcv@EdIxGTn!!A|pc)MdC{1ozg+X;K&tE z6)g4WjPeNH8Dq(CzacAxj07TKU`&O4IAoycDi)y8qKDlgN5dhHdCE1QpEXo^=i?!Z zQ$FNO68HH`UN99%4we;Z{d^`bKP4>C7S?f`Ow;8bc%QqApJnei_1S0dGr2IUgl3fT zV-ad|PYlxwjov9sr!pp#=wFC_X{b6!qmkFr>od7WI?CXuiY|s~Fbj|#0*_~23VyU}P*t6no-2H-xYw2y1iTIG% z*a2q*!WDQF6iat}%_#l_Zc@bXDQSc=kRtv~4E$W5xTu4ZCW#b@-y6^KN@sjhL&#DF-yD0dfU6 zPk%UiP9#%eDg(9(xGS!supZ3Ta6UhMu?8_$g)FR+XQ|)2HpEBCr-tg+V$T&vn4M1EXq|?}Z2c!CzLRWiy#hpeT5+rGeMd~|Z0Y09fjyIr*kjTIXrCqyUv?LmIWiQa06?p z#^m_QpG8D96a74*O6i^bqKT-y)NrH3{U1WqfXVb{Jli~FzfYM;bG@oU)XWahUv(F*U9;-Gott?HtqP32e3`UnITKo!7 zBB=nyS;XW5{r0{}Sl}xbu^<()_?5OPF4Qb2wz*j3&;d=goqD(_&RGALYg3%Dj3+Q2 z1O;~u?3&D4Jj6~|b(XQIXY0a>1Kr}yj7iDEVpq#}q8O1<^in>T3>6-G7N(oc$?sDd z>4^&oO%i}@p&PXw1n~a}4Orp4;V6p4l}Y}@h~2E6DR?Om>5wg8l+|e9g5uDi33oz6 z(DrbXRVj@k5Wx?X18X}7U}`I8m-rP7l|)muo-Vm)Wg6@AR@UY>Xnn2t+=_tt2JNjC zA9r%X1QvNR~>@W(=a=`H;{^G8)cF06R?RyY_w|HLh#wW)>+$IwtNjd|Qkiv&6Pz z_dC_!_B%VI6R~)djyt5kM>;B%A|B->w)8$>hAI3zXX;&o-|rIq7IZ>vdt}W^v~xt3 zeO5@Ly$TI+mYv39qZ%UW~JSFCuse3&LtRvs`8nM799|5919H>BliVMuwLpB5F) zk*5u;h{=t`-5|?Y&N8Km8jEQZ5(EKD4%uOLGb3au+3!;pr_tPg92AU{iw75a_te&l z;o4tPzTCTXv!_cNWAql*!VR+A#=3TSuO??0gE4=Y@+c%Mo^dJS38n%|4tW)zxMK(f zMb%-&@G)fBy6OR|Z1Pn!O4-MmdmT)DiOD$176qeLC&6k6EAzq<#l>Q0euY80_Q&Fp zY#EJG-aD$QX)X(fQcN;u(ghKN-&l~E3E`>2O8PV%uY|^Bp%e@LwTkjpi^flEu90}f zm75Ww$dF5wIw)v}Aq9z=asr`2RY=p;*omMtgE}6OSj1i1+C`(PTwk(zzla>D)OF|? zsr5FmVz5R^z}<(peZ_nGZ9i+IO5DBXaM$C1MUN|3mJ}Cp535_0%ehIWE9hmd%3S&J zb&Bd-nB8pG92IN(J}Z7vwCj&!5>N#`xOpB8x$7iRV({W9kD(ZgE4ytvTd7aZv@!G6 zEt2)?_LeOi19n5^44pO4OKY1r}p5;dW#Q(acH$tulX` zsS|e5j#OXevuyrK#iEosDutA1mz|m-a$$yk*1f#=p;W1U{b{XgX9mu0zUmefZN13X zP8NA#7ZAG6z*ZVCjJ4PBfGdutCZb3Y5t~|3b1_8%Ocf&r3S%|d6GJ4^4auWr^H->e zrLts#73UA`gx=Kb)y^N(x4Prm(=dERb60nD?8VA+=Ug7VkqNBMopame-AyyxYqnt=M5{l-|dt+b);`+&9#`ffGS1fP}0KOtvYYdZ7&;=o7MTt z;Jo8G%;31Kd0e*ViFhQgue0c0Ui`3ul}8p$q5<}LKC791cyhhmcg1KHSBd9285T`SI|zNKYhFEKVOHJSMO#2Z%~Z=N=(EWmuVaF{HMz zY&0jz0v%%~L=1EAZBo~Ee*1MH|H=2fkPW5|xd(VnMujwpi_LZhaRt&X;+GI`sJWYc zN+l&c9tt_Z%nGb>rrb%w3p6xuAH^6J7zfOBHeiR|R>qbt$88nLm=*bDOVht$_P2;L z{luLKZ;K%61|m~TY>PPO#reuIm!mADlf6*{+Y{%s*>{Pc>F9apOdO88m+|I5#zJ8c z;vB$~ycN-O!iopyyX1Iid9Ty$>=JjF*HC}0(=i3QLasENiiC4b&;To@DK4~ND?r@o zc07*;0aNN{5wd0A9zjbo5n+A_XCvH&fle6>-$|abH!uN;|9k0RXZ+u6g%SSx5AJyh zO~=dnJu#K92l+&Xg`Tpad5hTDvJOuAR$)4ju3N+*Y>5C{1SkMNZ^22EGi=7Q#i+2H zZK2%W5-i=y)HayR#t6E|PUfcfOE&+RCJB#0Y!v!3zh^}au}`A~T(Y@|3$6*?)-QS7 z1O&p5hi?msjr9dHP`8K+>=q%JR;e4=>!yBU^Nf_5mVmGZY^o*IJCnH%RmO>8vEoqR z71knXm~NRq9%qN0yF`fzBPpLSr8~HyF)YfF{u+}CB%bRhLMaYqC+0Y;37h6pm8qfp ze0H~TN!~NGg5SH{ZhcKgLzVRlG7^(|fjbmUlJ=kC6uwF5?^Bi)cFbqvk3XDv3ZwXc zCWEJsSsd7F>7hEfi*%SoImW*4o6_4Xo*jBtle9%LPma#c-n}_};pIx^%pUw6damw? zq=ZY@hQ&7v$mK@jX2sK+qCOk%Dtut7sk_f5n=c&k(y7+oc0hXoon7|#!a@|H?zI#pdU?51PZHC4`cc1b$s zicIKlLb`RGF!f4lgpCT5=e>?;JYq`kj}ga;!uow)uh*@29xc8-5bzY z^HfMC0;rT*yXXkg)V*-an_<+R*CoGbDxe-@>Lg!OV45BH1+a$n_uiIi-38#fhRc^g zqX#@MG7}~qBxwIyZTk@r7WVr`a0>t#Q$+?^dl%9~r$)(`4p_SZbSj_ay zU(tEN)oN>BI|ZsWi#^wj8Zv3JxS=9cUJ42p3D4LFnd{iN8jR*_D?63iVvwGb3ITZ} z$OyLHwplm3&>x21#t&06)Pjq~bHbIHGSz-a)X~irgPI zhqnUDu0|Tq^*rWa!N7l~nZ63K>4S~2xr42K+?j?gR=!Bkr| zFl&p~&TRkV?BL^sk8p~6TiHLmQ^mRgRZQ)eRbpPnBb+>oLn_GZKr_oPiVdd`iFkae zkQeO8dc;EI`gEEK$!Vl|k|`0*SXTqL5C4DAO@vCjIUqRCJ*U4mnA9|fvLM)kbu|t! zUU#`wj`g6WR6$k{y7lI{O@}A+PAC4^Gv&tOykg8?0S^YV9aa} zyTsN&-1qm$wru2RVd)3iV!3l&$yZJ>p5Ogcwr z4<2SF*$eSO@(d&Pa zpN?O@*d>gkBkxlJ^(TZRd;;6K@12=qGIsFHdk?Ny9*~H}qbVIRG7>X}hXe_e6RvQB rq;cp)e8O!#iwZjaH*|%{{d51^Kljf!`TYL@00960yP(Q40Nw-uwbRNt literal 0 HcmV?d00001 diff --git a/deployment/deployment/quanxiang_charts/organizations/.helmignore b/deployment/charts/quanxiang/charts/organizations/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/organizations/.helmignore rename to deployment/charts/quanxiang/charts/organizations/.helmignore diff --git a/deployment/charts/quanxiang/charts/organizations/Chart.yaml b/deployment/charts/quanxiang/charts/organizations/Chart.yaml new file mode 100644 index 0000000..cdac09f --- /dev/null +++ b/deployment/charts/quanxiang/charts/organizations/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: organizations +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/deployment/deployment/quanxiang_charts/organizations/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/organizations/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/organizations/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/organizations/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/organizations/templates/configmap.yaml b/deployment/charts/quanxiang/charts/organizations/templates/configmap.yaml similarity index 74% rename from deployment/deployment/quanxiang_charts/organizations/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/organizations/templates/configmap.yaml index 349fa51..229918b 100644 --- a/deployment/deployment/quanxiang_charts/organizations/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/organizations/templates/configmap.yaml @@ -2,7 +2,7 @@ kind: ConfigMap apiVersion: v1 metadata: name: organizations - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} data: config.yml: |- @@ -18,11 +18,11 @@ data: #-------------------mysql配置--------------------- mysql: - db: {{ .Values.config.mysql.db }} - host: {{ .Values.config.mysql.host }} - user: {{ .Values.config.mysql.user }} - password: {{ .Values.config.mysql.password }} - log: {{ .Values.config.mysql.log }} + db: {{ .Values.mysql.db }} + host: {{ .Values.mysql.host }} + user: {{ .Values.mysql.user }} + password: {{ .Values.mysql.password }} + log: {{ .Values.mysql.log }} # -------------------- log -------------------- # comply with zap log specification @@ -39,12 +39,13 @@ data: #-------------------redis配置----------------- redis: - {{- with .Values.config.redis.addrs }} + {{- with .Values.redis.addrs }} addrs: {{- toYaml . | nindent 8 }} {{- end }} - username: {{ .Values.config.redis.username }} - password: {{ .Values.config.redis.password }} + username: {{ .Values.redis.username }} + password: {{ .Values.redis.password }} + # ----------------------redis缓存的verificationCode---------------------- verificationCode: @@ -67,11 +68,11 @@ data: # -------------------- elastic -------------------- elastic: - {{- with .Values.config.elastic.host }} + {{- with.Values.elastic.host }} host: {{- toYaml . | nindent 8 }} {{- end }} - log: {{ .Values.config.elastic.log }} + log: {{ .Values.elastic.log }} ldap: @@ -97,8 +98,8 @@ data: #-------------------mysql配置--------------------- mysql: - db: {{ .Values.config.mysql.db }} - host: {{ .Values.config.mysql.host }} - user: {{ .Values.config.mysql.user }} - password: {{ .Values.config.mysql.password }} - log: {{ .Values.config.mysql.log }} + db: {{ .Values.mysql.db }} + host: {{ .Values.mysql.host }} + user: {{ .Values.mysql.user }} + password: {{ .Values.mysql.password }} + log: {{ .Values.mysql.log }} diff --git a/deployment/deployment/quanxiang_charts/organizations/templates/deployment.yaml b/deployment/charts/quanxiang/charts/organizations/templates/deployment.yaml similarity index 93% rename from deployment/deployment/quanxiang_charts/organizations/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/organizations/templates/deployment.yaml index 7d5a6bc..00c4a9c 100644 --- a/deployment/deployment/quanxiang_charts/organizations/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/organizations/templates/deployment.yaml @@ -2,7 +2,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: org - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: org app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} @@ -39,7 +39,7 @@ spec: defaultMode: 420 containers: - name: container - image: '{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }}' + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' ports: - name: org containerPort: 80 diff --git a/deployment/deployment/quanxiang_charts/organizations/templates/service.yaml b/deployment/charts/quanxiang/charts/organizations/templates/service.yaml similarity index 94% rename from deployment/deployment/quanxiang_charts/organizations/templates/service.yaml rename to deployment/charts/quanxiang/charts/organizations/templates/service.yaml index 3970de4..eea4872 100644 --- a/deployment/deployment/quanxiang_charts/organizations/templates/service.yaml +++ b/deployment/charts/quanxiang/charts/organizations/templates/service.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: org - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: org app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} diff --git a/deployment/deployment/quanxiang_charts/organizations/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/organizations/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/organizations/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/organizations/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/organizations/values.yaml b/deployment/charts/quanxiang/charts/organizations/values.yaml new file mode 100644 index 0000000..c1ca718 --- /dev/null +++ b/deployment/charts/quanxiang/charts/organizations/values.yaml @@ -0,0 +1,20 @@ +image: + repository: docker.io/quanxiang/organizations + tag: v2.0.0 +namespace: "" + +mysql: {} + +redis: {} + +elastic: {} + +app: + kubernetes: + io: + name: backend + +service: + type: ClusterIP + port: 80 + rpcPort: 0 \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/persona/.helmignore b/deployment/charts/quanxiang/charts/persona/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/persona/.helmignore rename to deployment/charts/quanxiang/charts/persona/.helmignore diff --git a/deployment/charts/quanxiang/charts/persona/Chart.yaml b/deployment/charts/quanxiang/charts/persona/Chart.yaml new file mode 100644 index 0000000..00ae104 --- /dev/null +++ b/deployment/charts/quanxiang/charts/persona/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: persona +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/deployment/deployment/quanxiang_charts/persona/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/persona/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/persona/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/persona/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/persona/templates/configmap.yaml b/deployment/charts/quanxiang/charts/persona/templates/configmap.yaml similarity index 83% rename from deployment/deployment/quanxiang_charts/persona/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/persona/templates/configmap.yaml index a035e2d..573c279 100644 --- a/deployment/deployment/quanxiang_charts/persona/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/persona/templates/configmap.yaml @@ -2,9 +2,7 @@ kind: ConfigMap apiVersion: v1 metadata: name: persona - namespace: {{ .Values.namespace }} - annotations: - kubesphere.io/creator: zhenlinding + namespace: {{ .Release.Namespace }} data: config.yml: |- # model 模式 debug|release @@ -31,11 +29,11 @@ data: #-------------------es配置----------------- elasticsearch: - {{- with .Values.config.elastic.host }} + {{- with .Values.elastic.host }} host: {{- toYaml . | nindent 8 }} {{- end }} - log: {{ .Values.config.elastic.log }} + log: {{ .Values.elastic.log }} timeout: 5 cafingerprint: defaultindex: "persona_kv" # 初始化默认存储index diff --git a/deployment/deployment/quanxiang_charts/persona/templates/deployment.yaml b/deployment/charts/quanxiang/charts/persona/templates/deployment.yaml similarity index 92% rename from deployment/deployment/quanxiang_charts/persona/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/persona/templates/deployment.yaml index 88f43b1..6546618 100644 --- a/deployment/deployment/quanxiang_charts/persona/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/persona/templates/deployment.yaml @@ -2,7 +2,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: persona - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: persona app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} @@ -38,8 +38,8 @@ spec: name: persona defaultMode: 420 containers: - - name: container - image: '{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }}' + - name: persona + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' ports: - name: http-web containerPort: 80 diff --git a/deployment/deployment/quanxiang_charts/persona/templates/service.yaml b/deployment/charts/quanxiang/charts/persona/templates/service.yaml similarity index 93% rename from deployment/deployment/quanxiang_charts/persona/templates/service.yaml rename to deployment/charts/quanxiang/charts/persona/templates/service.yaml index d6cf85e..2399a3b 100644 --- a/deployment/deployment/quanxiang_charts/persona/templates/service.yaml +++ b/deployment/charts/quanxiang/charts/persona/templates/service.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: persona - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: persona app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} diff --git a/deployment/deployment/quanxiang_charts/persona/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/persona/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/persona/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/persona/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/persona/values.yaml b/deployment/charts/quanxiang/charts/persona/values.yaml new file mode 100644 index 0000000..fada2e7 --- /dev/null +++ b/deployment/charts/quanxiang/charts/persona/values.yaml @@ -0,0 +1,16 @@ +image: + repository: docker.io/quanxiang/persona + tag: v2.0.0 +namespace: "" +elastic: {} +imagePullSecrets: "" + +service: + type: ClusterIP + port: 80 + rpcPort: 0 + +app: + kubernetes: + io: + name: lowcode diff --git a/deployment/deployment/quanxiang_charts/polyapi/.helmignore b/deployment/charts/quanxiang/charts/polyapi/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/polyapi/.helmignore rename to deployment/charts/quanxiang/charts/polyapi/.helmignore diff --git a/deployment/charts/quanxiang/charts/polyapi/Chart.yaml b/deployment/charts/quanxiang/charts/polyapi/Chart.yaml new file mode 100644 index 0000000..bc07b00 --- /dev/null +++ b/deployment/charts/quanxiang/charts/polyapi/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: polyapi +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/deployment/deployment/quanxiang_charts/polyapi/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/polyapi/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/polyapi/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/polyapi/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/polyapi/templates/configmap.yaml b/deployment/charts/quanxiang/charts/polyapi/templates/configmap.yaml similarity index 84% rename from deployment/deployment/quanxiang_charts/polyapi/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/polyapi/templates/configmap.yaml index b47b1eb..c602c9a 100644 --- a/deployment/deployment/quanxiang_charts/polyapi/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/polyapi/templates/configmap.yaml @@ -2,7 +2,7 @@ kind: ConfigMap apiVersion: v1 metadata: name: polyapi - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} data: config.yml: | @@ -89,18 +89,18 @@ data: # -------------------- mysql -------------------- mysql: - db: {{ .Values.config.mysql.db }} - host: {{ .Values.config.mysql.host }} - user: {{ .Values.config.mysql.user }} - password: {{ .Values.config.mysql.password }} - log: {{ .Values.config.mysql.log }} + db: {{ .Values.mysql.db }} + host: {{ .Values.mysql.host }} + user: {{ .Values.mysql.user }} + password: {{ .Values.mysql.password }} + log: {{ .Values.mysql.log }} # -------------------- redis -------------------- redis: - {{- with .Values.config.redis.addrs }} + {{- with .Values.redis.addrs }} addrs: {{- toYaml . | nindent 8 }} {{- end }} - username: {{ .Values.config.redis.username }} - password: {{ .Values.config.redis.password }} + username: {{ .Values.redis.username }} + password: {{ .Values.redis.password }} diff --git a/deployment/deployment/quanxiang_charts/polyapi/templates/deployment.yaml b/deployment/charts/quanxiang/charts/polyapi/templates/deployment.yaml similarity index 92% rename from deployment/deployment/quanxiang_charts/polyapi/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/polyapi/templates/deployment.yaml index 7d74490..615daf5 100644 --- a/deployment/deployment/quanxiang_charts/polyapi/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/polyapi/templates/deployment.yaml @@ -70,13 +70,6 @@ spec: serviceAccountName: default serviceAccount: default securityContext: {} - {{- if .Values.args.enabled }} - hostAliases: - - hostnames: - - fs.{{ .Values.domain }} - - default.fs.{{ .Values.domain }} - ip: {{ .Values.args.ip }} - {{- end }} imagePullSecrets: - name: {{ .Values.imagePullSecrets }} affinity: {} diff --git a/deployment/deployment/quanxiang_charts/polyapi/templates/ingress.yaml b/deployment/charts/quanxiang/charts/polyapi/templates/ingress.yaml similarity index 93% rename from deployment/deployment/quanxiang_charts/polyapi/templates/ingress.yaml rename to deployment/charts/quanxiang/charts/polyapi/templates/ingress.yaml index 2d067ef..c5d31bb 100644 --- a/deployment/deployment/quanxiang_charts/polyapi/templates/ingress.yaml +++ b/deployment/charts/quanxiang/charts/polyapi/templates/ingress.yaml @@ -2,7 +2,7 @@ kind: Ingress apiVersion: networking.k8s.io/v1 metadata: name: polyapi-qxp - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/proxy-body-size: 30m diff --git a/deployment/deployment/quanxiang_charts/polyapi/templates/service.yaml b/deployment/charts/quanxiang/charts/polyapi/templates/service.yaml similarity index 95% rename from deployment/deployment/quanxiang_charts/polyapi/templates/service.yaml rename to deployment/charts/quanxiang/charts/polyapi/templates/service.yaml index c9cdeb2..83dbea8 100644 --- a/deployment/deployment/quanxiang_charts/polyapi/templates/service.yaml +++ b/deployment/charts/quanxiang/charts/polyapi/templates/service.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: polyapi - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: polyapi app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} diff --git a/deployment/deployment/quanxiang_charts/polyapi/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/polyapi/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/polyapi/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/polyapi/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/polyapi/values.yaml b/deployment/charts/quanxiang/charts/polyapi/values.yaml new file mode 100644 index 0000000..c5c56fc --- /dev/null +++ b/deployment/charts/quanxiang/charts/polyapi/values.yaml @@ -0,0 +1,25 @@ +image: + repository: docker.io/quanxiang/polyapi + tag: v2.0.0 +namespace: "" + +mysql: {} +redis: {} +service: + type: ClusterIP + port: 80 + rpcPort: 9090 + +app: + kubernetes: + io: + name: backend + +ingress: + enabled: true + hosts: + - host: polyapi.example.com + paths: + - fullName: polyapi + path: / + svcPort: 80 diff --git a/deployment/deployment/quanxiang_charts/polygate/.helmignore b/deployment/charts/quanxiang/charts/polygate/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/polygate/.helmignore rename to deployment/charts/quanxiang/charts/polygate/.helmignore diff --git a/deployment/charts/quanxiang/charts/polygate/Chart.yaml b/deployment/charts/quanxiang/charts/polygate/Chart.yaml new file mode 100644 index 0000000..322612e --- /dev/null +++ b/deployment/charts/quanxiang/charts/polygate/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: polygate +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/deployment/deployment/quanxiang_charts/polygate/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/polygate/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/polygate/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/polygate/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/polygate/templates/configmap.yaml b/deployment/charts/quanxiang/charts/polygate/templates/configmap.yaml similarity index 92% rename from deployment/deployment/quanxiang_charts/polygate/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/polygate/templates/configmap.yaml index 569679a..3ca59cf 100644 --- a/deployment/deployment/quanxiang_charts/polygate/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/polygate/templates/configmap.yaml @@ -2,7 +2,7 @@ kind: ConfigMap apiVersion: v1 metadata: name: polygate - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} annotations: kubesphere.io/creator: zhenlinding data: @@ -95,9 +95,9 @@ data: # -------------------- redis -------------------- redis: - {{- with .Values.config.redis.addrs }} + {{- with .Values.redis.addrs }} addrs: {{- toYaml . | nindent 8 }} {{- end }} - username: {{ .Values.config.redis.username }} - password: {{ .Values.config.redis.password }} + username: {{ .Values.redis.username }} + password: {{ .Values.redis.password }} diff --git a/deployment/deployment/quanxiang_charts/polygate/templates/deployment.yaml b/deployment/charts/quanxiang/charts/polygate/templates/deployment.yaml similarity index 93% rename from deployment/deployment/quanxiang_charts/polygate/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/polygate/templates/deployment.yaml index 0b46d52..2b436cd 100644 --- a/deployment/deployment/quanxiang_charts/polygate/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/polygate/templates/deployment.yaml @@ -2,7 +2,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: polygate - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: polygate app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} @@ -39,7 +39,7 @@ spec: defaultMode: 420 containers: - name: container - image: '{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }}' + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' ports: - name: http-web containerPort: 80 diff --git a/deployment/deployment/quanxiang_charts/polygate/templates/ingress.yaml b/deployment/charts/quanxiang/charts/polygate/templates/ingress.yaml similarity index 93% rename from deployment/deployment/quanxiang_charts/polygate/templates/ingress.yaml rename to deployment/charts/quanxiang/charts/polygate/templates/ingress.yaml index ff478c6..52cf5fe 100644 --- a/deployment/deployment/quanxiang_charts/polygate/templates/ingress.yaml +++ b/deployment/charts/quanxiang/charts/polygate/templates/ingress.yaml @@ -2,7 +2,7 @@ kind: Ingress apiVersion: networking.k8s.io/v1 metadata: name: polygate - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app.kubernetes.io/version: v1 annotations: diff --git a/deployment/deployment/quanxiang_charts/polygate/templates/service.yaml b/deployment/charts/quanxiang/charts/polygate/templates/service.yaml similarity index 94% rename from deployment/deployment/quanxiang_charts/polygate/templates/service.yaml rename to deployment/charts/quanxiang/charts/polygate/templates/service.yaml index 1f99f0e..95b97f5 100644 --- a/deployment/deployment/quanxiang_charts/polygate/templates/service.yaml +++ b/deployment/charts/quanxiang/charts/polygate/templates/service.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: polygate - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: polygate app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} diff --git a/deployment/deployment/quanxiang_charts/polygate/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/polygate/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/polygate/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/polygate/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/polygate/values.yaml b/deployment/charts/quanxiang/charts/polygate/values.yaml new file mode 100644 index 0000000..f9076eb --- /dev/null +++ b/deployment/charts/quanxiang/charts/polygate/values.yaml @@ -0,0 +1,37 @@ +image: + repository: quanxiang/polygate + tag: v2.0.0 +namespace: "" +domain: example.com + +imagePullSecrets: "" +service: + type: ClusterIP + port: 80 + rpcPort: 9090 + +redis: + addrs: + - redis-cluster-0.redis-cluster-headless.{{.}}.svc.cluster.local:6379 + - redis-cluster-1.redis-cluster-headless.{{.}}.svc.cluster.local:6379 + - redis-cluster-2.redis-cluster-headless.{{.}}.svc.cluster.local:6379 + username: "" + password: qxp1234 + +ingress: + enabled: true + hosts: + - host: ws.example.com + paths: + - fullName: message + path: / + svcPort: 8080 + - host: api.example.com + paths: + - fullName: polygate + path: / + svcPort: 80 +app: + kubernetes: + io: + name: lowcode diff --git a/deployment/deployment/quanxiang_charts/process/.helmignore b/deployment/charts/quanxiang/charts/process/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/process/.helmignore rename to deployment/charts/quanxiang/charts/process/.helmignore diff --git a/deployment/charts/quanxiang/charts/process/Chart.yaml b/deployment/charts/quanxiang/charts/process/Chart.yaml new file mode 100644 index 0000000..3114a2e --- /dev/null +++ b/deployment/charts/quanxiang/charts/process/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: process +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/deployment/deployment/quanxiang_charts/process/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/process/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/process/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/process/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/process/templates/configmap.yaml b/deployment/charts/quanxiang/charts/process/templates/configmap.yaml similarity index 70% rename from deployment/deployment/quanxiang_charts/process/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/process/templates/configmap.yaml index 4290007..b0f54ef 100644 --- a/deployment/deployment/quanxiang_charts/process/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/process/templates/configmap.yaml @@ -2,7 +2,7 @@ kind: ConfigMap apiVersion: v1 metadata: name: process - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} data: config.yml: |+ @@ -14,11 +14,11 @@ data: #-------------------mysql配置--------------------- mysql: - db: {{ .Values.config.mysql.db }} - host: {{ .Values.config.mysql.host }} - user: {{ .Values.config.mysql.user }} - password: {{ .Values.config.mysql.password }} - log: {{ .Values.config.mysql.log }} + db: {{ .Values.mysql.db }} + host: {{ .Values.mysql.host }} + user: {{ .Values.mysql.user }} + password: {{ .Values.mysql.password }} + log: {{ .Values.mysql.log }} @@ -42,12 +42,12 @@ data: #-------------------redis配置----------------- redis: - {{- with .Values.config.redis.addrs }} + {{- with .Values.redis.addrs }} addrs: {{- toYaml . | nindent 8 }} {{- end }} - username: {{ .Values.config.redis.username }} - password: {{ .Values.config.redis.password }} + username: {{ .Values.redis.username }} + password: {{ .Values.redis.password }} # -------------------- internal server client -------------------- api: orgHost: http://org diff --git a/deployment/deployment/quanxiang_charts/process/templates/deployment.yaml b/deployment/charts/quanxiang/charts/process/templates/deployment.yaml similarity index 93% rename from deployment/deployment/quanxiang_charts/process/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/process/templates/deployment.yaml index 71c1f60..82290db 100644 --- a/deployment/deployment/quanxiang_charts/process/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/process/templates/deployment.yaml @@ -2,7 +2,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: process - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: process app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} @@ -39,7 +39,7 @@ spec: defaultMode: 420 containers: - name: container - image: '{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }}' + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' ports: - name: process containerPort: 80 diff --git a/deployment/deployment/quanxiang_charts/process/templates/service.yaml b/deployment/charts/quanxiang/charts/process/templates/service.yaml similarity index 94% rename from deployment/deployment/quanxiang_charts/process/templates/service.yaml rename to deployment/charts/quanxiang/charts/process/templates/service.yaml index 00ec86d..6b381e3 100644 --- a/deployment/deployment/quanxiang_charts/process/templates/service.yaml +++ b/deployment/charts/quanxiang/charts/process/templates/service.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: process - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: process app.kubernetes.io/name: {{ .Values.app.kubernetes.io.name }} diff --git a/deployment/deployment/quanxiang_charts/process/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/process/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/process/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/process/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/process/values.yaml b/deployment/charts/quanxiang/charts/process/values.yaml new file mode 100644 index 0000000..ad577e4 --- /dev/null +++ b/deployment/charts/quanxiang/charts/process/values.yaml @@ -0,0 +1,22 @@ +image: + repository: docker.io/quanxiang/process + tag: v2.0.0 +namespace: "" +imagePullSecrets: "" +mysql: + db: process + host: mysql.{{.}}.svc.cluster.local:3306 + user: root + password: qxp1234 + log: true +redis: {} + +app: + kubernetes: + io: + name: backend + +service: + type: ClusterIP + port: 80 + rpcPort: 0 \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/qxp-web-home/.helmignore b/deployment/charts/quanxiang/charts/qxp-web-home/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/qxp-web-home/.helmignore rename to deployment/charts/quanxiang/charts/qxp-web-home/.helmignore diff --git a/deployment/charts/quanxiang/charts/qxp-web-home/Chart.yaml b/deployment/charts/quanxiang/charts/qxp-web-home/Chart.yaml new file mode 100644 index 0000000..e1b51d3 --- /dev/null +++ b/deployment/charts/quanxiang/charts/qxp-web-home/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: qxp-web-home +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/deployment/deployment/quanxiang_charts/audit/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/qxp-web-home/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/audit/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/qxp-web-home/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/qxp-web-home/templates/configmap.yaml b/deployment/charts/quanxiang/charts/qxp-web-home/templates/configmap.yaml similarity index 59% rename from deployment/deployment/quanxiang_charts/qxp-web-home/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/qxp-web-home/templates/configmap.yaml index 380f183..e96906b 100644 --- a/deployment/deployment/quanxiang_charts/qxp-web-home/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/qxp-web-home/templates/configmap.yaml @@ -2,7 +2,7 @@ kind: ConfigMap apiVersion: v1 metadata: name: qxp-web-home-config - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} annotations: kubesphere.io/alias-name: qxp-web-home-config @@ -22,14 +22,12 @@ data: idle_conn_timeout: 90 redis: - {{- with .Values.config.redis.addrs }} + {{- with .Values.redis.addrs }} addrs: {{- toYaml . | nindent 8 }} {{- end }} - username: {{ .Values.config.redis.username }} - password: {{ .Values.config.redis.password }} - timeout: {{ .Values.config.redis.timeout }} - + username: {{ .Values.redis.username }} + password: {{ .Values.redis.password }} portal_server: server_port: 80 log_level: debug @@ -49,11 +47,11 @@ data: enable_stdout: true client_config: - websocket_hostname: {{ .Values.websocket_hostname }} - home_hostname: {{ .Values.home_hostname }} - portal_hostname: {{ .Values.portal_hostname }} + websocket_hostname: {{ or .Values.global.websocket_hostname .Values.websocket_hostname }} + home_hostname: {{ or .Values.global.home_hostname .Values.home_hostname }} + portal_hostname: {{ or .Values.global.portal_hostname .Values.portal_hostname }} docs_hostname: docs.clouden.io vendor: - protocol: {{ .Values.vendor.protocol }} - hostname: {{ .Values.vendor.hostname }} - port: {{ .Values.vendor.port }} \ No newline at end of file + protocol: {{ or .Values.global.vendor.protocol .Values.vendor.protocol }} + hostname: {{ or .Values.global.vendor.hostname .Values.vendor.hostname }} + port: {{ or .Values.global.vendor.port .Values.vendor.port }} \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/qxp-web-home/templates/deployment.yaml b/deployment/charts/quanxiang/charts/qxp-web-home/templates/deployment.yaml similarity index 86% rename from deployment/deployment/quanxiang_charts/qxp-web-home/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/qxp-web-home/templates/deployment.yaml index 0b21c45..4c2e514 100644 --- a/deployment/deployment/quanxiang_charts/qxp-web-home/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/qxp-web-home/templates/deployment.yaml @@ -2,7 +2,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: qxp-web-home - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: qxp-web-home version: v1 @@ -38,7 +38,7 @@ spec: defaultMode: 420 containers: - name: qxp-web-home - image: {{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }} + image: {{ .Values.image.repository }}:{{ .Values.image.tag }} ports: - name: home containerPort: 80 @@ -56,12 +56,6 @@ spec: dnsPolicy: ClusterFirst serviceAccountName: default serviceAccount: default - {{- if .Values.args.enabled }} - hostAliases: - - hostnames: - - vendors.{{ .Values.domain }} - ip: {{ .Values.args.ip }} - {{- end }} securityContext: {} imagePullSecrets: - name: {{ .Values.imagePullSecrets }} diff --git a/deployment/deployment/quanxiang_charts/qxp-web-home/templates/service.yaml b/deployment/charts/quanxiang/charts/qxp-web-home/templates/service.yaml similarity index 93% rename from deployment/deployment/quanxiang_charts/qxp-web-home/templates/service.yaml rename to deployment/charts/quanxiang/charts/qxp-web-home/templates/service.yaml index 7063ced..108d6e4 100644 --- a/deployment/deployment/quanxiang_charts/qxp-web-home/templates/service.yaml +++ b/deployment/charts/quanxiang/charts/qxp-web-home/templates/service.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: qxp-web-home - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: qxp-web-home version: v1 diff --git a/deployment/deployment/quanxiang_charts/qxp-web-home/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/qxp-web-home/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/qxp-web-home/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/qxp-web-home/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/qxp-web-home/values.yaml b/deployment/charts/quanxiang/charts/qxp-web-home/values.yaml new file mode 100644 index 0000000..0660088 --- /dev/null +++ b/deployment/charts/quanxiang/charts/qxp-web-home/values.yaml @@ -0,0 +1,23 @@ +image: + repository: docker.io/quanxiang/qxp-web-home + tag: v2.0.0 +imagePullSecrets: "" +namespace: "" +websocket_hostname: ws.example.com +home_hostname: home.example.com +portal_hostname: portal.example.com +vendor: + protocol: http + hostname: vendors.example.com + port: 80 +domain: example.com +service: + type: ClusterIP + port: 80 + rpcPort: 0 +redis: {} + +app: + kubernetes: + io: + name: fronted diff --git a/deployment/deployment/quanxiang_charts/qxp-web-nginx/.helmignore b/deployment/charts/quanxiang/charts/qxp-web-nginx/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/qxp-web-nginx/.helmignore rename to deployment/charts/quanxiang/charts/qxp-web-nginx/.helmignore diff --git a/deployment/charts/quanxiang/charts/qxp-web-nginx/Chart.yaml b/deployment/charts/quanxiang/charts/qxp-web-nginx/Chart.yaml new file mode 100644 index 0000000..2ba9aac --- /dev/null +++ b/deployment/charts/quanxiang/charts/qxp-web-nginx/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: qxp-web-nginx +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/deployment/deployment/quanxiang_charts/message/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/qxp-web-nginx/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/message/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/qxp-web-nginx/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/qxp-web-nginx/templates/deployment.yaml b/deployment/charts/quanxiang/charts/qxp-web-nginx/templates/deployment.yaml similarity index 92% rename from deployment/deployment/quanxiang_charts/qxp-web-nginx/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/qxp-web-nginx/templates/deployment.yaml index db8b71a..130df78 100644 --- a/deployment/deployment/quanxiang_charts/qxp-web-nginx/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/qxp-web-nginx/templates/deployment.yaml @@ -2,7 +2,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: qxp-web-nginx - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: qxp-web-nginx version: v1 @@ -31,7 +31,7 @@ spec: spec: containers: - name: container-hdjghs - image: {{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }} + image: {{ .Values.image.repository }}:{{ .Values.image.tag }} ports: - name: http-nginx containerPort: 80 diff --git a/deployment/deployment/quanxiang_charts/qxp-web-nginx/templates/service.yaml b/deployment/charts/quanxiang/charts/qxp-web-nginx/templates/service.yaml similarity index 93% rename from deployment/deployment/quanxiang_charts/qxp-web-nginx/templates/service.yaml rename to deployment/charts/quanxiang/charts/qxp-web-nginx/templates/service.yaml index 582e3bf..64ee4e3 100644 --- a/deployment/deployment/quanxiang_charts/qxp-web-nginx/templates/service.yaml +++ b/deployment/charts/quanxiang/charts/qxp-web-nginx/templates/service.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: qxp-web-nginx - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: qxp-web-nginx version: v1 diff --git a/deployment/deployment/quanxiang_charts/qxp-web-nginx/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/qxp-web-nginx/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/qxp-web-nginx/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/qxp-web-nginx/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/qxp-web-nginx/values.yaml b/deployment/charts/quanxiang/charts/qxp-web-nginx/values.yaml new file mode 100644 index 0000000..98170fa --- /dev/null +++ b/deployment/charts/quanxiang/charts/qxp-web-nginx/values.yaml @@ -0,0 +1,17 @@ +image: + repository: docker.io/quanxiang/qxp-web-nginx + tag: v2.0.0 +imagePullSecrets: "" +namespace: "" +service: + type: ClusterIP + port: 80 + rpcPort: 0 +app: + kubernetes: + io: + name: fronted + + + + diff --git a/deployment/deployment/quanxiang_charts/qxp-web-portal/.helmignore b/deployment/charts/quanxiang/charts/qxp-web-portal/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/qxp-web-portal/.helmignore rename to deployment/charts/quanxiang/charts/qxp-web-portal/.helmignore diff --git a/deployment/charts/quanxiang/charts/qxp-web-portal/Chart.yaml b/deployment/charts/quanxiang/charts/qxp-web-portal/Chart.yaml new file mode 100644 index 0000000..4374c05 --- /dev/null +++ b/deployment/charts/quanxiang/charts/qxp-web-portal/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: qxp-web-portal +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/deployment/deployment/quanxiang_charts/qxp-web-home/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/qxp-web-portal/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/qxp-web-home/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/qxp-web-portal/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/qxp-web-portal/templates/configmap.yaml b/deployment/charts/quanxiang/charts/qxp-web-portal/templates/configmap.yaml similarity index 59% rename from deployment/deployment/quanxiang_charts/qxp-web-portal/templates/configmap.yaml rename to deployment/charts/quanxiang/charts/qxp-web-portal/templates/configmap.yaml index 734f45e..cd5252a 100644 --- a/deployment/deployment/quanxiang_charts/qxp-web-portal/templates/configmap.yaml +++ b/deployment/charts/quanxiang/charts/qxp-web-portal/templates/configmap.yaml @@ -2,7 +2,7 @@ kind: ConfigMap apiVersion: v1 metadata: name: qxp-web-portal-config - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} annotations: kubesphere.io/alias-name: qxp-web-portal-config @@ -22,15 +22,12 @@ data: idle_conn_timeout: 90 redis: - {{- with .Values.config.redis.addrs }} + {{- with .Values.redis.addrs }} addrs: {{- toYaml . | nindent 8 }} {{- end }} - username: {{ .Values.config.redis.username }} - password: {{ .Values.config.redis.password }} - timeout: {{ .Values.config.redis.timeout }} - - + username: {{ .Values.redis.username }} + password: {{ .Values.redis.password }} portal_server: server_port: 80 log_level: debug @@ -50,11 +47,11 @@ data: enable_stdout: true client_config: - websocket_hostname: {{ .Values.websocket_hostname }} - home_hostname: {{ .Values.home_hostname }} - portal_hostname: {{ .Values.portal_hostname }} + websocket_hostname: {{ or .Values.global.websocket_hostname .Values.websocket_hostname }} + home_hostname: {{ or .Values.global.home_hostname .Values.home_hostname }} + portal_hostname: {{ or .Values.global.portal_hostname .Values.portal_hostname }} docs_hostname: docs.clouden.io vendor: - protocol: {{ .Values.vendor.protocol }} - hostname: {{ .Values.vendor.hostname }} - port: {{ .Values.vendor.port }} \ No newline at end of file + protocol: {{ or .Values.global.vendor.protocol .Values.vendor.protocol }} + hostname: {{ or .Values.global.vendor.hostname .Values.vendor.hostname }} + port: {{ or .Values.global.vendor.port .Values.vendor.port }} \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/qxp-web-portal/templates/deployment.yaml b/deployment/charts/quanxiang/charts/qxp-web-portal/templates/deployment.yaml similarity index 86% rename from deployment/deployment/quanxiang_charts/qxp-web-portal/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/qxp-web-portal/templates/deployment.yaml index 916fe6a..b60d4a0 100644 --- a/deployment/deployment/quanxiang_charts/qxp-web-portal/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/qxp-web-portal/templates/deployment.yaml @@ -2,7 +2,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: qxp-web-portal - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: qxp-web-portal version: v1 @@ -38,7 +38,7 @@ spec: defaultMode: 420 containers: - name: qxp-web-portal - image: {{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }} + image: {{ .Values.image.repository }}:{{ .Values.image.tag }} ports: - name: portal containerPort: 80 @@ -56,12 +56,6 @@ spec: dnsPolicy: ClusterFirst serviceAccountName: default serviceAccount: default - {{- if .Values.args.enabled }} - hostAliases: - - hostnames: - - vendors.{{ .Values.domain }} - ip: {{ .Values.args.ip }} - {{- end }} securityContext: {} imagePullSecrets: - name: {{ .Values.imagePullSecrets }} diff --git a/deployment/deployment/quanxiang_charts/qxp-web-portal/templates/ingress.yml b/deployment/charts/quanxiang/charts/qxp-web-portal/templates/ingress.yml similarity index 55% rename from deployment/deployment/quanxiang_charts/qxp-web-portal/templates/ingress.yml rename to deployment/charts/quanxiang/charts/qxp-web-portal/templates/ingress.yml index 634baa5..76c9669 100644 --- a/deployment/deployment/quanxiang_charts/qxp-web-portal/templates/ingress.yml +++ b/deployment/charts/quanxiang/charts/qxp-web-portal/templates/ingress.yml @@ -10,17 +10,20 @@ metadata: kubernetes.io/ingress.class: nginx spec: rules: - {{- range .Values.ingress.hosts }} - - host: {{ .host | quote }} + - host: {{ or .Values.global.portal_hostname .Values.portal_hostname }} http: paths: - {{- range .paths }} - - path: {{ .path }} + - path: / pathType: Prefix backend: service: - name: {{ .fullName }} + name: qxp-web-portal port: - number: {{ .svcPort }} - {{- end }} - {{- end }} \ No newline at end of file + number: 80 + - path: / + pathType: Prefix + backend: + service: + name: qxp-web-nginx + port: + number: 80 \ No newline at end of file diff --git a/deployment/deployment/quanxiang_charts/qxp-web-portal/templates/service.yaml b/deployment/charts/quanxiang/charts/qxp-web-portal/templates/service.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/qxp-web-portal/templates/service.yaml rename to deployment/charts/quanxiang/charts/qxp-web-portal/templates/service.yaml diff --git a/deployment/deployment/quanxiang_charts/qxp-web-portal/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/qxp-web-portal/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/qxp-web-portal/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/qxp-web-portal/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/qxp-web-portal/values.yaml b/deployment/charts/quanxiang/charts/qxp-web-portal/values.yaml new file mode 100644 index 0000000..bf3fca7 --- /dev/null +++ b/deployment/charts/quanxiang/charts/qxp-web-portal/values.yaml @@ -0,0 +1,27 @@ +image: + repository: docker.io/quanxiang/qxp-web-portal + tag: v2.0.0 +namespace: "" +websocket_hostname: ws.example.com +home_hostname: home.example.com +portal_hostname: portal.example.com +vendor: + protocol: http + hostname: vendors.example.com + port: 80 +service: + type: ClusterIP + port: 80 + rpcPort: 0 +redis: + addrs: + - redis-cluster-0.redis-cluster-headless:6379 + - redis-cluster-1.redis-cluster-headless:6379 + - redis-cluster-2.redis-cluster-headless:6379 + username: "" + password: qxp1234 + +app: + kubernetes: + io: + name: fronted diff --git a/deployment/deployment/quanxiang_charts/qxp-web-vendors/.helmignore b/deployment/charts/quanxiang/charts/qxp-web-vendors/.helmignore similarity index 100% rename from deployment/deployment/quanxiang_charts/qxp-web-vendors/.helmignore rename to deployment/charts/quanxiang/charts/qxp-web-vendors/.helmignore diff --git a/deployment/charts/quanxiang/charts/qxp-web-vendors/Chart.yaml b/deployment/charts/quanxiang/charts/qxp-web-vendors/Chart.yaml new file mode 100644 index 0000000..8faf269 --- /dev/null +++ b/deployment/charts/quanxiang/charts/qxp-web-vendors/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: qxp-web-vendors +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/deployment/deployment/quanxiang_charts/qxp-web-nginx/templates/_helpers.tpl b/deployment/charts/quanxiang/charts/qxp-web-vendors/templates/_helpers.tpl similarity index 100% rename from deployment/deployment/quanxiang_charts/qxp-web-nginx/templates/_helpers.tpl rename to deployment/charts/quanxiang/charts/qxp-web-vendors/templates/_helpers.tpl diff --git a/deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/deployment.yaml b/deployment/charts/quanxiang/charts/qxp-web-vendors/templates/deployment.yaml similarity index 93% rename from deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/deployment.yaml rename to deployment/charts/quanxiang/charts/qxp-web-vendors/templates/deployment.yaml index 6a22593..211e920 100644 --- a/deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/deployment.yaml +++ b/deployment/charts/quanxiang/charts/qxp-web-vendors/templates/deployment.yaml @@ -2,7 +2,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: qxp-web-vendors - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: qxp-web-vendors version: v1 @@ -33,7 +33,7 @@ spec: spec: containers: - name: qxp-web-vendors - image: {{ .Values.image.repo }}/{{ .Values.image.name }}:{{ .Values.image.tag }} + image: {{ .Values.image.repository }}:{{ .Values.image.tag }} ports: - name: portal containerPort: 80 diff --git a/deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/ingress.yml b/deployment/charts/quanxiang/charts/qxp-web-vendors/templates/ingress.yml similarity index 57% rename from deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/ingress.yml rename to deployment/charts/quanxiang/charts/qxp-web-vendors/templates/ingress.yml index 7f250fd..3f725fa 100644 --- a/deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/ingress.yml +++ b/deployment/charts/quanxiang/charts/qxp-web-vendors/templates/ingress.yml @@ -2,7 +2,7 @@ kind: Ingress apiVersion: networking.k8s.io/v1 metadata: name: qxp-web-vendors - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app.kubernetes.io/version: v1 annotations: @@ -10,17 +10,13 @@ metadata: kubernetes.io/ingress.class: nginx spec: rules: - {{- range .Values.ingress.hosts }} - - host: {{ .host | quote }} + - host: {{ or .Values.global.vendor.hostname .Values.vendor.hostname }} http: paths: - {{- range .paths }} - - path: {{ .path }} + - path: / pathType: Prefix backend: service: - name: {{ .fullName }} + name: qxp-web-vendors port: - number: {{ .svcPort }} - {{- end }} - {{- end }} \ No newline at end of file + number: 80 diff --git a/deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/service.yaml b/deployment/charts/quanxiang/charts/qxp-web-vendors/templates/service.yaml similarity index 93% rename from deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/service.yaml rename to deployment/charts/quanxiang/charts/qxp-web-vendors/templates/service.yaml index 8952f04..15e601b 100644 --- a/deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/service.yaml +++ b/deployment/charts/quanxiang/charts/qxp-web-vendors/templates/service.yaml @@ -2,7 +2,7 @@ kind: Service apiVersion: v1 metadata: name: qxp-web-vendors - namespace: {{ .Values.namespace }} + namespace: {{ .Release.Namespace }} labels: app: qxp-web-vendors version: v1 diff --git a/deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/tests/test-connection.yaml b/deployment/charts/quanxiang/charts/qxp-web-vendors/templates/tests/test-connection.yaml similarity index 100% rename from deployment/deployment/quanxiang_charts/qxp-web-vendors/templates/tests/test-connection.yaml rename to deployment/charts/quanxiang/charts/qxp-web-vendors/templates/tests/test-connection.yaml diff --git a/deployment/charts/quanxiang/charts/qxp-web-vendors/values.yaml b/deployment/charts/quanxiang/charts/qxp-web-vendors/values.yaml new file mode 100644 index 0000000..e359ff4 --- /dev/null +++ b/deployment/charts/quanxiang/charts/qxp-web-vendors/values.yaml @@ -0,0 +1,17 @@ +image: + repository: docker.io/quanxiang/qxp-web-vendors + tag: v2.0.0 +namespace: "" +imagePullSecrets: "" +vendor: + protocol: "" + hostname: "" + port: 0 +service: + type: ClusterIP + port: 80 + rpcPort: 0 +app: + kubernetes: + io: + name: fronted diff --git a/deployment/charts/quanxiang/charts/redis-cluster-7.1.0.tgz b/deployment/charts/quanxiang/charts/redis-cluster-7.1.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..b0f6a4dc1b5a9c7cfc943de5ee5570cd92d68253 GIT binary patch literal 97445 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