From 9dd419d84513974a204429e558f9e8f8b16c17ae Mon Sep 17 00:00:00 2001 From: jenkins Date: Wed, 28 May 2025 10:01:42 +0300 Subject: [PATCH] update repo --- README.md | 93 + argo-infra-apps/cassandra.yaml | 265 ++ argo-infra-apps/elasticsearch.yaml | 258 ++ argo-infra-apps/grafana.yaml | 233 ++ argo-infra-apps/ingress-nginx.yaml | 208 ++ argo-infra-apps/kafka.yaml | 359 ++ argo-infra-apps/livekit-egress.yaml | 122 + argo-infra-apps/livekit-server.yaml | 194 + .../nfs-subdir-external-provisione.yaml | 233 ++ argo-infra-apps/postgres.yaml | 206 + argo-infra-apps/postgresql-ha.yaml | 20 + argo-infra-apps/redis.yaml | 287 ++ argo-infra-apps/vault-secrets-operator.yaml | 908 +++++ argo-infra-apps/vault.yaml | 442 +++ caddy/.helmignore | 26 + caddy/Chart.yaml | 29 + caddy/LICENSE | 19 + caddy/README.md | 64 + caddy/templates/NOTES.txt | 22 + caddy/templates/_helpers.tpl | 75 + caddy/templates/configmap.yaml | 11 + caddy/templates/deployment.yaml | 105 + caddy/templates/hpa.yaml | 28 + caddy/templates/ingress.yaml | 61 + caddy/templates/service.yaml | 36 + caddy/templates/serviceaccount.yaml | 12 + caddy/templates/tests/test-connection.yaml | 19 + caddy/values.yaml | 180 + cassandra/.helmignore | 25 + cassandra/Chart.lock | 6 + cassandra/Chart.yaml | 34 + cassandra/README.md | 574 +++ cassandra/charts/common/.helmignore | 26 + cassandra/charts/common/Chart.yaml | 23 + cassandra/charts/common/README.md | 235 ++ .../charts/common/templates/_affinities.tpl | 155 + .../charts/common/templates/_capabilities.tpl | 253 ++ .../common/templates/_compatibility.tpl | 46 + cassandra/charts/common/templates/_errors.tpl | 85 + cassandra/charts/common/templates/_images.tpl | 115 + .../charts/common/templates/_ingress.tpl | 73 + cassandra/charts/common/templates/_labels.tpl | 46 + cassandra/charts/common/templates/_names.tpl | 71 + .../charts/common/templates/_resources.tpl | 50 + .../charts/common/templates/_secrets.tpl | 192 + .../charts/common/templates/_storage.tpl | 21 + .../charts/common/templates/_tplvalues.tpl | 52 + cassandra/charts/common/templates/_utils.tpl | 77 + .../charts/common/templates/_warnings.tpl | 109 + .../templates/validations/_cassandra.tpl | 51 + .../common/templates/validations/_mariadb.tpl | 108 + .../common/templates/validations/_mongodb.tpl | 67 + .../common/templates/validations/_mysql.tpl | 67 + .../templates/validations/_postgresql.tpl | 105 + .../common/templates/validations/_redis.tpl | 48 + .../templates/validations/_validations.tpl | 51 + cassandra/charts/common/values.yaml | 8 + cassandra/templates/NOTES.txt | 96 + cassandra/templates/_helpers.tpl | 282 ++ cassandra/templates/cassandra-secret.yaml | 39 + cassandra/templates/extra-list.yaml | 9 + cassandra/templates/headless-svc.yaml | 33 + cassandra/templates/init_cm.yaml | 7 + cassandra/templates/initdb-configmap.yaml | 19 + cassandra/templates/metrics-configmap.yaml | 19 + cassandra/templates/networkpolicy.yaml | 82 + cassandra/templates/pdb.yaml | 26 + cassandra/templates/service.yaml | 59 + cassandra/templates/serviceaccount.yaml | 18 + cassandra/templates/servicemonitor.yaml | 46 + cassandra/templates/statefulset.yaml | 690 ++++ cassandra/templates/tls-secret.yaml | 30 + cassandra/values.yaml | 972 +++++ compose/ansible.cfg | 28 + .../custom_inventory/group_vars/all/all.yaml | 1 + .../host_vars/cw-sya-reg-001/common.yml | 4 + .../cw-sya-reg-001/files/ssl/docker.crt | 78 + .../cw-sya-reg-001/files/ssl/docker.key | 90 + compose/custom_inventory/hosts | 18 + compose/inventory/hosts | 8 + compose/playbooks/ca_server/README.md | 4 + compose/playbooks/ca_server/ansible.cfg | 4 + compose/playbooks/ca_server/defaults/main.yml | 9 + compose/playbooks/ca_server/handlers/main.yml | 5 + compose/playbooks/ca_server/inventory/hosts | 3 + compose/playbooks/ca_server/main.yml | 16 + .../ca_server/roles/ca_install/README.md | 4 + .../roles/ca_install/handlers/main.yml | 4 + .../roles/ca_install/tasks/configure_ca.yml | 51 + .../roles/ca_install/tasks/create_cert.yml | 45 + .../ca_server/roles/ca_install/tasks/main.yml | 8 + .../ca_install/templates/template.cnf.j2 | 22 + .../ca_server/roles/ca_install/vars/main.yml | 2 + .../ca_server/tasks/check_os_version.yml | 15 + .../playbooks/ca_server/vars/base_conf.yml | 10 + compose/playbooks/ca_server/vars/secret.yml | 10 + compose/playbooks/dns_server/README.md | 4 + compose/playbooks/dns_server/ansible.cfg | 4 + .../playbooks/dns_server/defaults/main.yml | 9 + .../playbooks/dns_server/handlers/main.yml | 5 + compose/playbooks/dns_server/inventory/hosts | 3 + compose/playbooks/dns_server/main.yml | 16 + .../dns_server/roles/bind_install/README.md | 4 + .../roles/bind_install/handlers/main.yml | 4 + .../bind_install/tasks/configure_bind.yml | 124 + .../roles/bind_install/tasks/install_bind.yml | 17 + .../roles/bind_install/tasks/main.yml | 9 + .../bind_install/templates/dns_zone_local.j2 | 17 + .../templates/named.conf.local.j2 | 6 + .../templates/named.conf.options.j2 | 12 + .../roles/bind_install/vars/main.yml | 2 + .../dns_server/tasks/check_os_version.yml | 15 + .../playbooks/dns_server/vars/base_conf.yml | 5 + .../playbooks/dns_server/vars/dns_zone.yml | 16 + compose/playbooks/infra-base_admin.yml | 50 + compose/playbooks/infra-docker-registry.yml | 8 + compose/playbooks/keycloak_server/README.md | 4 + compose/playbooks/keycloak_server/ansible.cfg | 4 + .../keycloak_server/defaults/main.yml | 9 + .../keycloak_server/handlers/main.yml | 5 + .../playbooks/keycloak_server/inventory/hosts | 4 + compose/playbooks/keycloak_server/main.yml | 18 + .../roles/docker_install/README.md | 4 + .../roles/docker_install/handlers/main.yml | 4 + .../docker_install/tasks/configure_docker.yml | 29 + .../docker_install/tasks/install_docker.yml | 35 + .../roles/docker_install/tasks/main.yml | 9 + .../docker_install/templates/daemon.json.j2 | 7 + .../roles/docker_install/vars/main.yml | 7 + .../roles/keycloak_install_docker/README.md | 4 + .../keycloak_install_docker/handlers/main.yml | 4 + .../tasks/install_keycloak.yml | 57 + .../keycloak_install_docker/tasks/main.yml | 6 + .../templates/compose.yml.j2 | 44 + .../keycloak_install_docker/vars/main.yml | 2 + .../tasks/check_os_version.yml | 15 + .../keycloak_server/vars/base_conf.yml | 5 + .../playbooks/keycloak_server/vars/secret.yml | 189 + compose/playbooks/openldap_server/README.md | 4 + compose/playbooks/openldap_server/ansible.cfg | 4 + .../openldap_server/defaults/main.yml | 9 + .../openldap_server/handlers/main.yml | 5 + .../playbooks/openldap_server/inventory/hosts | 4 + compose/playbooks/openldap_server/main.yml | 18 + .../roles/docker_install/README.md | 4 + .../roles/docker_install/handlers/main.yml | 4 + .../docker_install/tasks/configure_docker.yml | 29 + .../docker_install/tasks/install_docker.yml | 35 + .../roles/docker_install/tasks/main.yml | 9 + .../docker_install/templates/daemon.json.j2 | 7 + .../roles/docker_install/vars/main.yml | 7 + .../roles/openldap_install_docker/README.md | 4 + .../files/cert/RootCA.crt | 22 + .../openldap_install_docker/handlers/main.yml | 4 + .../tasks/install_openldap.yml | 78 + .../openldap_install_docker/tasks/main.yml | 6 + .../templates/compose.yml.j2 | 61 + .../templates/haproxy.cfg.j2 | 23 + .../openldap_install_docker/vars/main.yml | 2 + .../tasks/check_os_version.yml | 15 + .../openldap_server/vars/base_conf.yml | 6 + .../playbooks/openldap_server/vars/secret.yml | 198 + compose/playbooks/prep_ubuntu/README.md | 4 + compose/playbooks/prep_ubuntu/ansible.cfg | 4 + .../playbooks/prep_ubuntu/defaults/main.yml | 9 + .../playbooks/prep_ubuntu/handlers/main.yml | 5 + compose/playbooks/prep_ubuntu/inventory/hosts | 6 + compose/playbooks/prep_ubuntu/main.yml | 22 + .../roles/ubuntu_base_conf/README.md | 4 + .../roles/ubuntu_base_conf/handlers/main.yml | 5 + .../ubuntu_base_conf/tasks/add_admin_user.yml | 46 + .../ubuntu_base_conf/tasks/apt_config.yml | 9 + .../ubuntu_base_conf/tasks/cert_ca_import.yml | 14 + .../ubuntu_base_conf/tasks/dnsmasq_config.yml | 75 + .../tasks/enable_services.yml | 16 + .../tasks/fstrim-timer_enable.yml | 8 + .../ubuntu_base_conf/tasks/history_config.yml | 4 + .../tasks/hosts_file_config.yml | 14 + .../ubuntu_base_conf/tasks/install-pkg.yml | 34 + .../tasks/journald_config.yml | 18 + .../tasks/logrotate_config.yml | 9 + .../roles/ubuntu_base_conf/tasks/main.yml | 79 + .../ubuntu_base_conf/tasks/profile_config.yml | 19 + .../ubuntu_base_conf/tasks/set_root_pass.yml | 7 + .../roles/ubuntu_base_conf/tasks/ssh_conf.yml | 22 + .../ubuntu_base_conf/tasks/swap_config.yml | 26 + .../ubuntu_base_conf/tasks/sysctl_config.yml | 19 + .../tasks/time_sync_config.yml | 24 + .../tasks/timezone_config.yml | 11 + .../roles/ubuntu_base_conf/tasks/ufw_conf.yml | 49 + .../tasks/update_packages.yml | 20 + .../apt/apt.conf.d/10-no-check-valid-until.j2 | 1 + .../ubuntu_base_conf/templates/etc/chrony.j2 | 39 + .../templates/etc/dhcp/dhclient.conf.j2 | 58 + .../templates/etc/dnsmasq.d/local-cache.j2 | 8 + .../templates/etc/logrotate.j2 | 21 + .../templates/etc/ssh/sshd_config.j2 | 140 + .../templates/etc/systemd/journald.j2 | 29 + .../roles/ubuntu_install_docker/README.md | 4 + .../ubuntu_install_docker/handlers/main.yml | 4 + .../tasks/configure_docker.yml | 29 + .../tasks/install_docker.yml | 35 + .../ubuntu_install_docker/tasks/main.yml | 9 + .../templates/daemon.json.j2 | 7 + .../roles/ubuntu_install_docker/vars/main.yml | 7 + .../prep_ubuntu/tasks/check_os_version.yml | 15 + .../playbooks/prep_ubuntu/tasks/reboot.yml | 9 + .../playbooks/prep_ubuntu/vars/base_conf.yml | 10 + compose/playbooks/prep_ubuntu/vars/secret.yml | 89 + compose/playbooks/s3_server/README.md | 4 + compose/playbooks/s3_server/ansible.cfg | 4 + compose/playbooks/s3_server/defaults/main.yml | 9 + compose/playbooks/s3_server/handlers/main.yml | 5 + compose/playbooks/s3_server/inventory/hosts | 3 + compose/playbooks/s3_server/main.yml | 16 + .../s3_server/roles/minio_install/README.md | 4 + .../roles/minio_install/handlers/main.yml | 4 + .../minio_install/tasks/configure_minio.yml | 191 + .../roles/minio_install/tasks/disk_layout.yml | 36 + .../minio_install/tasks/install_minio.yml | 12 + .../roles/minio_install/tasks/main.yml | 13 + .../roles/minio_install/templates/minio.j2 | 6 + .../roles/minio_install/vars/main.yml | 2 + .../s3_server/tasks/check_os_version.yml | 15 + .../playbooks/s3_server/vars/base_conf.yml | 17 + compose/playbooks/s3_server/vars/secret.yml | 608 +++ compose/roles/infra-common/tasks/main.yml | 17 + .../defaults/main.yml | 5 + .../handlers/main.yml | 2 + .../tasks/configure.yml | 18 + .../infra-container-registry/tasks/deploy.yml | 8 + .../tasks/install.yml | 5 + .../infra-container-registry/tasks/main.yml | 9 + .../templates/docker-compose.yml.j2 | 31 + elasticsearch/.helmignore | 2 + elasticsearch/Chart.yaml | 12 + elasticsearch/Makefile | 1 + elasticsearch/README.md | 490 +++ elasticsearch/examples/config/Makefile | 21 + elasticsearch/examples/config/README.md | 27 + elasticsearch/examples/config/test/goss.yaml | 31 + elasticsearch/examples/config/values.yaml | 29 + .../examples/config/watcher_encryption_key | 1 + elasticsearch/examples/default/Makefile | 14 + elasticsearch/examples/default/README.md | 25 + .../examples/default/rolling_upgrade.sh | 19 + elasticsearch/examples/default/test/goss.yaml | 44 + .../examples/docker-for-mac/Makefile | 13 + .../examples/docker-for-mac/README.md | 23 + .../examples/docker-for-mac/values.yaml | 23 + .../examples/kubernetes-kind/Makefile | 17 + .../examples/kubernetes-kind/README.md | 36 + .../kubernetes-kind/values-local-path.yaml | 23 + .../examples/kubernetes-kind/values.yaml | 23 + elasticsearch/examples/microk8s/Makefile | 13 + elasticsearch/examples/microk8s/README.md | 32 + elasticsearch/examples/microk8s/values.yaml | 32 + elasticsearch/examples/migration/Makefile | 10 + elasticsearch/examples/migration/README.md | 167 + elasticsearch/examples/migration/client.yaml | 19 + elasticsearch/examples/migration/data.yaml | 14 + elasticsearch/examples/migration/master.yaml | 23 + elasticsearch/examples/minikube/Makefile | 13 + elasticsearch/examples/minikube/README.md | 38 + elasticsearch/examples/minikube/values.yaml | 23 + elasticsearch/examples/multi/Makefile | 19 + elasticsearch/examples/multi/README.md | 29 + elasticsearch/examples/multi/client.yaml | 50 + elasticsearch/examples/multi/data.yaml | 48 + elasticsearch/examples/multi/master.yaml | 6 + elasticsearch/examples/multi/test/goss.yaml | 12 + elasticsearch/examples/networkpolicy/Makefile | 14 + .../examples/networkpolicy/values.yaml | 37 + elasticsearch/examples/openshift/Makefile | 13 + elasticsearch/examples/openshift/README.md | 24 + .../examples/openshift/test/goss.yaml | 20 + elasticsearch/examples/openshift/values.yaml | 11 + elasticsearch/examples/security/Makefile | 36 + elasticsearch/examples/security/README.md | 29 + .../examples/security/test/goss.yaml | 44 + elasticsearch/examples/security/values.yaml | 28 + elasticsearch/examples/upgrade/Makefile | 19 + elasticsearch/examples/upgrade/README.md | 17 + elasticsearch/examples/upgrade/test/goss.yaml | 22 + elasticsearch/examples/upgrade/values.yaml | 6 + elasticsearch/templates/NOTES.txt | 8 + elasticsearch/templates/_helpers.tpl | 97 + elasticsearch/templates/configmap.yaml | 34 + elasticsearch/templates/index_configmap.yaml | 265 ++ elasticsearch/templates/ingress.yaml | 64 + elasticsearch/templates/networkpolicy.yaml | 61 + .../templates/poddisruptionbudget.yaml | 15 + .../templates/podsecuritypolicy.yaml | 14 + elasticsearch/templates/role.yaml | 25 + elasticsearch/templates/rolebinding.yaml | 20 + elasticsearch/templates/secret-cert.yaml | 14 + elasticsearch/templates/secret.yaml | 23 + elasticsearch/templates/service.yaml | 78 + elasticsearch/templates/serviceaccount.yaml | 16 + elasticsearch/templates/statefulset.yaml | 427 +++ .../test/test-elasticsearch-health.yaml | 50 + elasticsearch/values.yaml | 682 ++++ grafana/Chart.yaml | 91 + grafana/charts/alloy-1.0.2.tgz | Bin 0 -> 25353 bytes .../.helmignore | 6 + .../Chart.lock | 3 + .../Chart.yaml | 13 + .../feature-annotation-autodiscovery/Makefile | 34 + .../README.md | 144 + .../README.md.gotmpl | 47 + .../templates/_helpers.tpl | 37 + .../templates/_module.alloy.tpl | 139 + .../templates/_notes.tpl | 11 + .../templates/_pods.alloy.tpl | 193 + .../templates/_services.alloy.tpl | 156 + .../templates/_validation.tpl | 14 + .../templates/configmap.yaml | 13 + .../tests/__snapshot__/.gitkeep | 0 .../tests/__snapshot__/default_test.yaml.snap | 300 ++ .../__snapshot__/namespaced_test.yaml.snap | 616 +++ .../__snapshot__/pods_only_test.yaml.snap | 221 ++ .../prometheus_annotation_test.yaml.snap | 300 ++ .../__snapshot__/selectors_test.yaml.snap | 308 ++ .../tests/default_test.yaml | 13 + .../tests/namespaced_test.yaml | 23 + .../tests/pods_only_test.yaml | 23 + .../tests/prometheus_annotation_test.yaml | 18 + .../tests/selectors_test.yaml | 23 + .../values.schema.json | 153 + .../values.yaml | 178 + .../.helmignore | 6 + .../Chart.lock | 3 + .../Chart.yaml | 13 + .../Makefile | 34 + .../README.md | 179 + .../README.md.gotmpl | 37 + .../schema-mods/types-and-enums.json | 13 + .../templates/_connector_host_info.tpl | 14 + .../templates/_connector_span_logs.tpl | 31 + .../templates/_connector_span_metrics.tpl | 51 + .../templates/_helpers.tpl | 30 + .../templates/_module.alloy.tpl | 36 + .../templates/_notes.tpl | 52 + .../templates/_pipeline.tpl | 161 + .../templates/_processor_batch.tpl | 21 + .../templates/_processor_filter.tpl | 74 + .../templates/_processor_interval.tpl | 23 + .../templates/_processor_k8sattributes.tpl | 55 + .../templates/_processor_memory_limiter.tpl | 20 + .../_processor_resourcedetection.tpl | 89 + .../templates/_processor_transform.tpl | 110 + .../templates/_receiver_jaeger.tpl | 36 + .../templates/_receiver_otlp.tpl | 36 + .../templates/_receiver_zipkin.tpl | 14 + .../templates/_validation.tpl | 16 + .../templates/configmap.yaml | 14 + .../tests/__snapshot__/.gitkeep | 0 .../tests/__snapshot__/default_test.yaml.snap | 161 + .../__snapshot__/interval_test.yaml.snap | 176 + .../tests/__snapshot__/jaeger_test.yaml.snap | 476 +++ .../__snapshot__/memorylimiter_test.yaml.snap | 126 + .../resourcedetection_test.yaml.snap | 353 ++ .../__snapshot__/spanlogs_test.yaml.snap | 145 + .../__snapshot__/spanmetrics_test.yaml.snap | 161 + .../tests/default_test.yaml | 30 + .../tests/interval_test.yaml | 33 + .../tests/jaeger_test.yaml | 57 + .../tests/memorylimiter_test.yaml | 20 + .../tests/resourcedetection_test.yaml | 52 + .../tests/spanlogs_test.yaml | 24 + .../tests/spanmetrics_test.yaml | 27 + .../tests/validation_test.yaml | 20 + .../values.schema.json | 461 +++ .../values.yaml | 350 ++ .../feature-auto-instrumentation/.helmignore | 6 + .../feature-auto-instrumentation/Chart.lock | 6 + .../feature-auto-instrumentation/Chart.yaml | 17 + .../feature-auto-instrumentation/Makefile | 36 + .../feature-auto-instrumentation/README.md | 74 + .../README.md.gotmpl | 35 + .../charts/beyla-1.7.3.tgz | Bin 0 -> 10382 bytes .../schema-mods/remote-beyla-config-data.jq | 1 + .../schema-mods/types-and-enums.json | 5 + .../templates/_helpers.tpl | 29 + .../templates/_module.alloy.tpl | 89 + .../templates/_notes.tpl | 13 + .../templates/configmap.yaml | 11 + .../openshift/beyla-scc.yaml | 66 + .../tests/__snapshot__/.gitkeep | 0 .../tests/default_test.yaml | 61 + .../values.schema.json | 113 + .../feature-auto-instrumentation/values.yaml | 122 + .../charts/feature-cluster-events/.helmignore | 6 + .../charts/feature-cluster-events/Chart.lock | 3 + .../charts/feature-cluster-events/Chart.yaml | 13 + .../charts/feature-cluster-events/Makefile | 34 + .../charts/feature-cluster-events/README.md | 65 + .../feature-cluster-events/README.md.gotmpl | 36 + .../templates/_helpers.tpl | 17 + .../templates/_module.alloy.tpl | 120 + .../templates/_notes.tpl | 11 + .../templates/configmap.yaml | 13 + .../tests/__snapshot__/default_test.yaml.snap | 79 + .../extra_processing_stages_test.yaml.snap | 84 + .../tests/__snapshot__/labels_test.yaml.snap | 79 + .../__snapshot__/namespace_test.yaml.snap | 80 + .../structured_metadata_test.yaml.snap | 87 + .../tests/default_test.yaml | 13 + .../tests/extra_processing_stages_test.yaml | 18 + .../tests/labels_test.yaml | 20 + .../tests/namespace_test.yaml | 14 + .../tests/structured_metadata_test.yaml | 17 + .../feature-cluster-events/values.schema.json | 39 + .../charts/feature-cluster-events/values.yaml | 53 + .../charts/feature-cluster-metrics/.ct.yaml | 4 + .../feature-cluster-metrics/.helmignore | 6 + .../charts/feature-cluster-metrics/Chart.lock | 18 + .../charts/feature-cluster-metrics/Chart.yaml | 39 + .../charts/feature-cluster-metrics/Makefile | 42 + .../charts/feature-cluster-metrics/README.md | 385 ++ .../feature-cluster-metrics/README.md.gotmpl | 104 + .../charts/kepler-0.5.13.tgz | Bin 0 -> 5092 bytes .../charts/kube-state-metrics-5.32.0.tgz | Bin 0 -> 15241 bytes .../charts/opencost-1.43.2.tgz | Bin 0 -> 17494 bytes .../prometheus-node-exporter-4.45.2.tgz | Bin 0 -> 14939 bytes .../prometheus-windows-exporter-0.10.0.tgz | Bin 0 -> 8208 bytes .../default-allow-lists/cadvisor.yaml | 20 + .../default-allow-lists/kepler.yaml | 3 + .../kube-state-metrics.yaml | 40 + .../default-allow-lists/kubelet.yaml | 38 + .../default-allow-lists/kubelet_probes.yaml | 3 + .../default-allow-lists/kubelet_resource.yaml | 4 + .../node-exporter-integration.yaml | 157 + .../default-allow-lists/node-exporter.yaml | 12 + .../default-allow-lists/opencost.yaml | 27 + .../default-allow-lists/windows-exporter.yaml | 7 + .../schema-mods/remove-subchart-fields.jq | 1 + .../schema-mods/types-and-enums.json | 17 + .../templates/_api_server.alloy.tpl | 95 + .../templates/_cadvisor.alloy.tpl | 200 + .../templates/_helpers.tpl | 17 + .../templates/_kepler.alloy.tpl | 79 + .../_kube_controller_manager.alloy.tpl | 68 + .../templates/_kube_dns.alloy.tpl | 140 + .../templates/_kube_proxy.alloy.tpl | 64 + .../templates/_kube_scheduler.alloy.tpl | 68 + .../templates/_kube_state_metrics.alloy.tpl | 102 + .../templates/_kubelet.alloy.tpl | 107 + .../templates/_kubelet_probes.alloy.tpl | 112 + .../templates/_kubelet_resource.alloy.tpl | 112 + .../templates/_module.alloy.tpl | 34 + .../templates/_node_exporter.alloy.tpl | 195 + .../templates/_notes.tpl | 47 + .../templates/_opencost.alloy.tpl | 79 + .../templates/_windows_exporter.alloy.tpl | 90 + .../templates/configmap.yaml | 13 + .../openshift/kepler-scc.yaml | 66 + .../tests/__snapshot__/.gitkeep | 0 .../alternative-discovery_test.yaml.snap | 1077 ++++++ .../__snapshot__/control_plane_test.yaml.snap | 742 ++++ .../__snapshot__/custom_rules_test.yaml.snap | 495 +++ .../tests/__snapshot__/default_test.yaml.snap | 477 +++ .../tests/__snapshot__/kepler_test.yaml.snap | 518 +++ .../metrics_tuning_test.yaml.snap | 477 +++ .../__snapshot__/opencost_test.yaml.snap | 518 +++ .../__snapshot__/openshift_test.yaml.snap | 477 +++ .../tests/alternative-discovery_test.yaml | 32 + .../tests/control_plane_test.yaml | 15 + .../tests/custom_rules_test.yaml | 38 + .../tests/default_test.yaml | 13 + .../tests/kepler_test.yaml | 15 + .../tests/metrics_tuning_test.yaml | 22 + .../tests/opencost_test.yaml | 15 + .../tests/openshift-kepler-scc_test.yaml | 45 + .../tests/openshift_test.yaml | 29 + .../values.schema.json | 1068 ++++++ .../feature-cluster-metrics/values.yaml | 1040 ++++++ .../charts/feature-integrations/.helmignore | 5 + .../charts/feature-integrations/Chart.lock | 3 + .../charts/feature-integrations/Chart.yaml | 13 + grafana/charts/feature-integrations/Makefile | 87 + grafana/charts/feature-integrations/README.md | 179 + .../feature-integrations/README.md.gotmpl | 110 + .../default-allow-lists/alloy.yaml | 105 + .../default-allow-lists/loki.yaml | 157 + .../default-allow-lists/mimir.yaml | 286 ++ .../default-allow-lists/tempo.yaml | 76 + .../integrations/.doc_templates/alloy.gotmpl | 39 + .../docs/integrations/alloy.md | 76 + .../docs/integrations/cert-manager.md | 40 + .../docs/integrations/etcd.md | 45 + .../docs/integrations/grafana.md | 50 + .../docs/integrations/loki.md | 50 + .../docs/integrations/mimir.md | 45 + .../docs/integrations/mysql.md | 68 + .../docs/integrations/tempo.md | 50 + .../integrations/alloy-values.yaml | 54 + .../integrations/cert-manager-values.yaml | 56 + .../integrations/etcd-values.yaml | 57 + .../integrations/grafana-values.yaml | 86 + .../integrations/loki-values.yaml | 85 + .../integrations/mimir-values.yaml | 85 + .../integrations/mysql-values.yaml | 107 + .../integrations/tempo-values.yaml | 85 + .../definitions/alloy-integration.schema.json | 55 + .../cert-manager-integration.schema.json | 60 + .../definitions/etcd-integration.schema.json | 60 + .../grafana-integration.schema.json | 88 + .../definitions/loki-integration.schema.json | 91 + .../definitions/mimir-integration.schema.json | 88 + .../definitions/mysql-integration.schema.json | 119 + .../definitions/tempo-integration.schema.json | 91 + .../schema-mods/integration-list.json | 19 + .../schema-mods/label-selectors.json | 53 + .../templates/_helpers.tpl | 120 + .../templates/_helpers_modules.tpl | 33 + .../templates/_integration_alloy.tpl | 291 ++ .../templates/_integration_cert-manager.tpl | 83 + .../templates/_integration_etcd.tpl | 83 + .../templates/_integration_grafana.tpl | 22 + .../templates/_integration_grafana_logs.tpl | 146 + .../_integration_grafana_metrics.tpl | 211 ++ .../templates/_integration_helpers.tpl | 21 + .../templates/_integration_loki.tpl | 22 + .../templates/_integration_loki_logs.tpl | 159 + .../templates/_integration_loki_metrics.tpl | 227 ++ .../templates/_integration_mimir.tpl | 22 + .../templates/_integration_mimir_logs.tpl | 159 + .../templates/_integration_mimir_metrics.tpl | 227 ++ .../templates/_integration_mysql.tpl | 48 + .../templates/_integration_mysql_logs.tpl | 81 + .../templates/_integration_mysql_metrics.tpl | 77 + .../templates/_integration_tempo.tpl | 22 + .../templates/_integration_tempo_logs.tpl | 159 + .../templates/_integration_tempo_metrics.tpl | 227 ++ .../templates/_integration_types.tpl | 11 + .../feature-integrations/templates/_notes.tpl | 26 + .../templates/_validation.tpl | 5 + .../templates/configmap.yaml | 49 + .../templates/mysql-secret.yaml | 19 + .../templates/secrets/_helpers.tpl | 188 + .../templates/secrets/_secret.alloy.tpl | 8 + .../__snapshot__/mysql_metrics_test.yaml.snap | 152 + .../tests/alloy_test.yaml | 326 ++ .../tests/cert-manager_test.yaml | 88 + .../feature-integrations/tests/etcd_test.yaml | 88 + .../tests/grafana_logs_test.yaml | 242 ++ .../tests/grafana_metrics_test.yaml | 308 ++ .../tests/loki_logs_test.yaml | 251 ++ .../tests/loki_metrics_test.yaml | 341 ++ .../tests/mimir_logs_test.yaml | 251 ++ .../tests/mimir_metrics_test.yaml | 341 ++ .../tests/mysql_logs_test.yaml | 108 + .../tests/mysql_metrics_test.yaml | 120 + .../tests/tempo_logs_test.yaml | 251 ++ .../tests/tempo_metrics_test.yaml | 358 ++ .../feature-integrations/values.schema.json | 851 +++++ .../charts/feature-integrations/values.yaml | 70 + grafana/charts/feature-node-logs/.helmignore | 6 + grafana/charts/feature-node-logs/Chart.lock | 3 + grafana/charts/feature-node-logs/Chart.yaml | 13 + grafana/charts/feature-node-logs/Makefile | 34 + grafana/charts/feature-node-logs/README.md | 79 + .../charts/feature-node-logs/README.md.gotmpl | 48 + .../templates/_collector_validation.tpl | 13 + .../feature-node-logs/templates/_helpers.tpl | 17 + .../templates/_module.alloy.tpl | 178 + .../feature-node-logs/templates/_notes.tpl | 11 + .../templates/configmap.yaml | 11 + .../tests/__snapshot__/.gitkeep | 0 .../feature-node-logs/tests/default_test.yaml | 160 + .../tests/filter_units_test.yaml | 171 + .../feature-node-logs/tests/labels_test.yaml | 165 + .../tests/structured_metadata_test.yaml | 176 + .../feature-node-logs/values.schema.json | 50 + grafana/charts/feature-node-logs/values.yaml | 71 + grafana/charts/feature-pod-logs/.helmignore | 6 + grafana/charts/feature-pod-logs/Chart.lock | 3 + grafana/charts/feature-pod-logs/Chart.yaml | 13 + grafana/charts/feature-pod-logs/Makefile | 34 + grafana/charts/feature-pod-logs/README.md | 100 + .../charts/feature-pod-logs/README.md.gotmpl | 32 + .../schema-mods/types-and-enums.json | 5 + .../feature-pod-logs/templates/_api.alloy.tpl | 15 + .../templates/_collector_validation.tpl | 79 + .../_common_log_processing.alloy.tpl | 93 + .../templates/_common_pod_discovery.alloy.tpl | 104 + .../templates/_filelog.alloy.tpl | 154 + .../feature-pod-logs/templates/_helpers.tpl | 30 + .../templates/_log_receiver.alloy.tpl | 10 + .../templates/_module.alloy.tpl | 25 + .../feature-pod-logs/templates/_notes.tpl | 12 + .../templates/_volumes.alloy.tpl | 38 + .../feature-pod-logs/templates/configmap.yaml | 13 + .../openshift-cluster-log-forwarder.yaml | 28 + .../tests/__snapshot__/.gitkeep | 0 .../tests/__snapshot__/default_test.yaml.snap | 870 +++++ .../feature-pod-logs/tests/default_test.yaml | 60 + .../feature-pod-logs/values.schema.json | 116 + grafana/charts/feature-pod-logs/values.yaml | 141 + grafana/charts/feature-profiling/.helmignore | 6 + grafana/charts/feature-profiling/Chart.lock | 3 + grafana/charts/feature-profiling/Chart.yaml | 13 + grafana/charts/feature-profiling/Makefile | 34 + grafana/charts/feature-profiling/README.md | 82 + .../charts/feature-profiling/README.md.gotmpl | 32 + .../schema-mods/types-and-enums.json | 9 + .../feature-profiling/templates/_ebpf.tpl | 88 + .../feature-profiling/templates/_helpers.tpl | 38 + .../feature-profiling/templates/_java.tpl | 100 + .../templates/_module.alloy.tpl | 13 + .../feature-profiling/templates/_notes.tpl | 12 + .../feature-profiling/templates/_pprof.tpl | 175 + .../templates/configmap.yaml | 13 + .../tests/__snapshot__/.gitkeep | 0 .../tests/__snapshot__/ebpf_test.yaml.snap | 179 + .../tests/__snapshot__/java_test.yaml.snap | 140 + .../tests/__snapshot__/pprof_test.yaml.snap | 1484 ++++++++ .../feature-profiling/tests/ebpf_test.yaml | 61 + .../feature-profiling/tests/java_test.yaml | 38 + .../feature-profiling/tests/pprof_test.yaml | 38 + .../feature-profiling/values.schema.json | 151 + grafana/charts/feature-profiling/values.yaml | 148 + .../.ct.yaml | 3 + .../.helmignore | 6 + .../Chart.lock | 6 + .../Chart.yaml | 18 + .../Makefile | 35 + .../README.md | 117 + .../README.md.gotmpl | 40 + .../prometheus-operator-crds-19.1.0.tgz | Bin 0 -> 394674 bytes .../templates/_helpers.tpl | 30 + .../templates/_module.alloy.tpl | 13 + .../templates/_notes.tpl | 24 + .../templates/_pod_monitors.alloy.tpl | 72 + .../templates/_probes.alloy.tpl | 72 + .../templates/_service_monitors.alloy.tpl | 72 + .../templates/_validations.tpl | 9 + .../templates/configmap.yaml | 13 + .../tests/__snapshot__/default_test.yaml.snap | 41 + .../labels_and_expressions_test.yaml.snap | 73 + .../tests/default_test.yaml | 13 + .../tests/labels_and_expressions_test.yaml | 31 + .../values.schema.json | 163 + .../values.yaml | 211 ++ grafana/destinations/loki-values.yaml | 203 + grafana/destinations/otlp-values.yaml | 335 ++ grafana/destinations/prometheus-values.yaml | 285 ++ grafana/destinations/pyroscope-values.yaml | 195 + grafana/templates/NOTES.txt | 34 + grafana/templates/_helpers.tpl | 58 + grafana/templates/_platform_validations.tpl | 52 + grafana/templates/_validations.tpl | 63 + grafana/templates/alloy-config.yaml | 42 + .../templates/alloy-modules-configmaps.yaml | 29 + grafana/templates/beyla-config.yaml | 41 + .../collectors/_collector_common.tpl | 24 + .../collectors/_collector_extraConfig.tpl | 5 + .../collectors/_collector_helpers.tpl | 52 + .../templates/collectors/_collector_notes.tpl | 11 + .../collectors/_collector_remoteConfig.tpl | 78 + .../collectors/_collector_validations.tpl | 20 + grafana/templates/destination_secret.yaml | 19 + .../templates/destinations/_config.alloy.tpl | 26 + .../destinations/_destination_helpers.tpl | 50 + .../destinations/_destination_loki.tpl | 154 + .../destinations/_destination_otlp.tpl | 442 +++ .../destinations/_destination_prometheus.tpl | 185 + .../destinations/_destination_pyroscope.tpl | 129 + .../destinations/_destination_types.tpl | 7 + .../destinations/_destination_validations.tpl | 75 + grafana/templates/extra-objects.yaml | 4 + .../_feature_annotation_autodiscovery.tpl | 50 + .../_feature_application_observability.tpl | 105 + .../_feature_auto_instrumentation.tpl | 49 + .../features/_feature_cluster_events.tpl | 49 + .../features/_feature_cluster_metrics.tpl | 195 + .../templates/features/_feature_helpers.tpl | 21 + .../features/_feature_integrations.tpl | 92 + .../templates/features/_feature_node_logs.tpl | 52 + .../templates/features/_feature_pod_logs.tpl | 55 + .../templates/features/_feature_profiling.tpl | 49 + .../_feature_prometheus_operator_obejcts.tpl | 50 + .../features/_feature_self_reporting.tpl | 92 + .../openshift/alloy-logs-scc.yaml | 84 + .../openshift/alloy-metrics-scc.yaml | 80 + .../openshift/alloy-profiles-scc.yaml | 80 + .../openshift/alloy-receiver-scc.yaml | 80 + .../openshift/alloy-singleton-scc.yaml | 80 + grafana/templates/receiver-service.yaml | 42 + grafana/templates/remote_config_secret.yaml | 25 + grafana/templates/secrets/_helpers.tpl | 188 + grafana/templates/secrets/_secret.alloy.tpl | 8 + grafana/templates/secrets/test/secrets.yaml | 130 + grafana/templates/test/helpers.yaml | 11 + grafana/templates/validations.yaml | 2 + grafana/values.yaml | 994 +++++ ingress-nginx/.helmignore | 23 + ingress-nginx/Chart.yaml | 23 + ingress-nginx/OWNERS | 4 + ingress-nginx/README.md | 564 +++ ingress-nginx/README.md.gotmpl | 247 ++ ingress-nginx/changelog/helm-chart-2.10.0.md | 9 + ingress-nginx/changelog/helm-chart-2.11.0.md | 10 + ingress-nginx/changelog/helm-chart-2.11.1.md | 9 + ingress-nginx/changelog/helm-chart-2.11.2.md | 9 + ingress-nginx/changelog/helm-chart-2.11.3.md | 9 + ingress-nginx/changelog/helm-chart-2.12.0.md | 10 + ingress-nginx/changelog/helm-chart-2.12.1.md | 9 + ingress-nginx/changelog/helm-chart-2.13.0.md | 10 + ingress-nginx/changelog/helm-chart-2.14.0.md | 9 + ingress-nginx/changelog/helm-chart-2.15.0.md | 9 + ingress-nginx/changelog/helm-chart-2.16.0.md | 9 + ingress-nginx/changelog/helm-chart-2.9.0.md | 9 + ingress-nginx/changelog/helm-chart-2.9.1.md | 9 + ingress-nginx/changelog/helm-chart-3.0.0.md | 9 + ingress-nginx/changelog/helm-chart-3.10.0.md | 9 + ingress-nginx/changelog/helm-chart-3.10.1.md | 9 + ingress-nginx/changelog/helm-chart-3.11.0.md | 9 + ingress-nginx/changelog/helm-chart-3.11.1.md | 9 + ingress-nginx/changelog/helm-chart-3.12.0.md | 9 + ingress-nginx/changelog/helm-chart-3.13.0.md | 9 + ingress-nginx/changelog/helm-chart-3.14.0.md | 9 + ingress-nginx/changelog/helm-chart-3.15.0.md | 9 + ingress-nginx/changelog/helm-chart-3.15.1.md | 9 + ingress-nginx/changelog/helm-chart-3.16.0.md | 9 + ingress-nginx/changelog/helm-chart-3.16.1.md | 9 + ingress-nginx/changelog/helm-chart-3.17.0.md | 9 + ingress-nginx/changelog/helm-chart-3.18.0.md | 10 + ingress-nginx/changelog/helm-chart-3.19.0.md | 9 + ingress-nginx/changelog/helm-chart-3.20.0.md | 9 + ingress-nginx/changelog/helm-chart-3.20.1.md | 10 + ingress-nginx/changelog/helm-chart-3.21.0.md | 12 + ingress-nginx/changelog/helm-chart-3.22.0.md | 10 + ingress-nginx/changelog/helm-chart-3.23.0.md | 9 + ingress-nginx/changelog/helm-chart-3.24.0.md | 9 + ingress-nginx/changelog/helm-chart-3.25.0.md | 9 + ingress-nginx/changelog/helm-chart-3.26.0.md | 9 + ingress-nginx/changelog/helm-chart-3.27.0.md | 9 + ingress-nginx/changelog/helm-chart-3.28.0.md | 9 + ingress-nginx/changelog/helm-chart-3.29.0.md | 9 + ingress-nginx/changelog/helm-chart-3.3.0.md | 12 + ingress-nginx/changelog/helm-chart-3.3.1.md | 12 + ingress-nginx/changelog/helm-chart-3.30.0.md | 9 + ingress-nginx/changelog/helm-chart-3.31.0.md | 9 + ingress-nginx/changelog/helm-chart-3.32.0.md | 9 + ingress-nginx/changelog/helm-chart-3.33.0.md | 9 + ingress-nginx/changelog/helm-chart-3.34.0.md | 9 + ingress-nginx/changelog/helm-chart-3.4.0.md | 9 + ingress-nginx/changelog/helm-chart-3.5.0.md | 9 + ingress-nginx/changelog/helm-chart-3.5.1.md | 9 + ingress-nginx/changelog/helm-chart-3.6.0.md | 9 + ingress-nginx/changelog/helm-chart-3.7.0.md | 9 + ingress-nginx/changelog/helm-chart-3.7.1.md | 9 + ingress-nginx/changelog/helm-chart-3.8.0.md | 13 + ingress-nginx/changelog/helm-chart-3.9.0.md | 9 + ingress-nginx/changelog/helm-chart-4.0.1.md | 9 + ingress-nginx/changelog/helm-chart-4.0.10.md | 9 + ingress-nginx/changelog/helm-chart-4.0.11.md | 9 + ingress-nginx/changelog/helm-chart-4.0.12.md | 9 + ingress-nginx/changelog/helm-chart-4.0.13.md | 9 + ingress-nginx/changelog/helm-chart-4.0.14.md | 9 + ingress-nginx/changelog/helm-chart-4.0.15.md | 43 + ingress-nginx/changelog/helm-chart-4.0.18.md | 40 + ingress-nginx/changelog/helm-chart-4.0.2.md | 9 + ingress-nginx/changelog/helm-chart-4.0.3.md | 9 + ingress-nginx/changelog/helm-chart-4.0.5.md | 9 + ingress-nginx/changelog/helm-chart-4.0.6.md | 12 + ingress-nginx/changelog/helm-chart-4.0.7.md | 10 + ingress-nginx/changelog/helm-chart-4.0.9.md | 9 + ingress-nginx/changelog/helm-chart-4.1.0.md | 21 + ingress-nginx/changelog/helm-chart-4.1.2.md | 11 + ingress-nginx/changelog/helm-chart-4.10.0.md | 9 + ingress-nginx/changelog/helm-chart-4.10.1.md | 11 + ingress-nginx/changelog/helm-chart-4.10.2.md | 18 + ingress-nginx/changelog/helm-chart-4.10.3.md | 9 + ingress-nginx/changelog/helm-chart-4.10.4.md | 9 + ingress-nginx/changelog/helm-chart-4.11.0.md | 18 + ingress-nginx/changelog/helm-chart-4.11.1.md | 9 + ingress-nginx/changelog/helm-chart-4.11.2.md | 9 + .../changelog/helm-chart-4.12.0-beta.0.md | 9 + ingress-nginx/changelog/helm-chart-4.12.0.md | 10 + ingress-nginx/changelog/helm-chart-4.12.1.md | 9 + ingress-nginx/changelog/helm-chart-4.12.2.md | 9 + ingress-nginx/changelog/helm-chart-4.2.0.md | 47 + ingress-nginx/changelog/helm-chart-4.2.1.md | 10 + ingress-nginx/changelog/helm-chart-4.3.0.md | 14 + ingress-nginx/changelog/helm-chart-4.4.0.md | 12 + ingress-nginx/changelog/helm-chart-4.5.2.md | 13 + ingress-nginx/changelog/helm-chart-4.6.0.md | 24 + ingress-nginx/changelog/helm-chart-4.6.1.md | 11 + ingress-nginx/changelog/helm-chart-4.7.0.md | 14 + ingress-nginx/changelog/helm-chart-4.7.1.md | 12 + ingress-nginx/changelog/helm-chart-4.7.2.md | 9 + .../changelog/helm-chart-4.8.0-beta.0.md | 13 + ingress-nginx/changelog/helm-chart-4.8.0.md | 13 + ingress-nginx/changelog/helm-chart-4.8.1.md | 9 + ingress-nginx/changelog/helm-chart-4.8.2.md | 10 + ingress-nginx/changelog/helm-chart-4.8.3.md | 9 + ingress-nginx/changelog/helm-chart-4.9.0.md | 13 + ingress-nginx/changelog/helm-chart-4.9.1.md | 10 + ingress-nginx/changelog/helm-chart.md.gotmpl | 11 + ...dmission-webhooks-cert-manager-values.yaml | 12 + ...ontroller-configmap-addheaders-values.yaml | 11 + ...troller-configmap-proxyheaders-values.yaml | 11 + .../ci/controller-configmap-values.yaml | 11 + .../controller-daemonset-metrics-values.yaml | 13 + ...oller-daemonset-podannotations-values.yaml | 16 + .../ci/controller-daemonset-values.yaml | 10 + .../controller-deployment-metrics-values.yaml | 13 + ...ller-deployment-podannotations-values.yaml | 16 + .../ci/controller-deployment-values.yaml | 10 + ingress-nginx/ci/controller-hpa-values.yaml | 18 + .../ci/controller-ingressclass-values.yaml | 15 + .../controller-service-internal-values.yaml | 13 + .../ci/controller-service-values.yaml | 22 + ingress-nginx/templates/NOTES.txt | 73 + ingress-nginx/templates/_helpers.tpl | 263 ++ ingress-nginx/templates/_params.tpl | 77 + .../admission-webhooks/cert-manager.yaml | 63 + .../job-patch/clusterrole.yaml | 23 + .../job-patch/clusterrolebinding.yaml | 23 + .../job-patch/job-createSecret.yaml | 79 + .../job-patch/job-patchWebhook.yaml | 81 + .../job-patch/networkpolicy.yaml | 26 + .../admission-webhooks/job-patch/role.yaml | 24 + .../job-patch/rolebinding.yaml | 24 + .../job-patch/serviceaccount.yaml | 17 + .../validating-webhook.yaml | 54 + ingress-nginx/templates/clusterrole.yaml | 102 + .../templates/clusterrolebinding.yaml | 19 + .../controller-configmap-addheaders.yaml | 14 + .../controller-configmap-proxyheaders.yaml | 14 + .../templates/controller-configmap-tcp.yaml | 17 + .../templates/controller-configmap-udp.yaml | 17 + .../templates/controller-configmap.yaml | 30 + .../templates/controller-daemonset.yaml | 236 ++ .../templates/controller-deployment.yaml | 242 ++ ingress-nginx/templates/controller-hpa.yaml | 47 + .../controller-ingressclass-aliases.yaml | 23 + .../templates/controller-ingressclass.yaml | 26 + ingress-nginx/templates/controller-keda.yaml | 46 + .../templates/controller-networkpolicy.yaml | 45 + .../controller-poddisruptionbudget.yaml | 39 + .../templates/controller-prometheusrule.yaml | 26 + ingress-nginx/templates/controller-role.yaml | 94 + .../templates/controller-rolebinding.yaml | 21 + .../templates/controller-secret.yaml | 15 + .../controller-service-internal.yaml | 105 + .../templates/controller-service-metrics.yaml | 45 + .../templates/controller-service-webhook.yaml | 40 + .../templates/controller-service.yaml | 105 + .../templates/controller-serviceaccount.yaml | 17 + .../templates/controller-servicemonitor.yaml | 50 + .../templates/default-backend-deployment.yaml | 119 + .../default-backend-extra-configmaps.yaml | 23 + .../templates/default-backend-hpa.yaml | 40 + .../default-backend-networkpolicy.yaml | 25 + .../default-backend-poddisruptionbudget.yaml | 32 + .../templates/default-backend-service.yaml | 41 + .../default-backend-serviceaccount.yaml | 14 + .../templates/service_additional.yaml | 19 + .../job-patch/clusterrole_test.yaml | 11 + .../job-patch/clusterrolebinding_test.yaml | 11 + .../job-patch/role_test.yaml | 11 + .../job-patch/rolebinding_test.yaml | 11 + .../job-patch/serviceaccount_test.yaml | 47 + .../validating-webhook_test.yaml | 32 + .../controller-configmap-addheaders_test.yaml | 27 + ...ontroller-configmap-proxyheaders_test.yaml | 27 + .../tests/controller-configmap_test.yaml | 31 + .../tests/controller-daemonset_test.yaml | 192 + .../tests/controller-deployment_test.yaml | 217 ++ ingress-nginx/tests/controller-hpa_test.yaml | 31 + .../controller-ingressclass-aliases_test.yaml | 110 + .../tests/controller-ingressclass_test.yaml | 93 + ingress-nginx/tests/controller-keda_test.yaml | 31 + .../tests/controller-networkpolicy_test.yaml | 23 + .../controller-poddisruptionbudget_test.yaml | 102 + .../tests/controller-prometheusrule_test.yaml | 29 + .../controller-service-internal_test.yaml | 25 + .../controller-service-metrics_test.yaml | 41 + .../controller-service-webhook_test.yaml | 32 + .../tests/controller-service_test.yaml | 32 + .../tests/controller-serviceaccount_test.yaml | 47 + .../tests/controller-servicemonitor_test.yaml | 29 + .../default-backend-deployment_test.yaml | 189 + ...default-backend-extra-configmaps_test.yaml | 50 + ...ault-backend-poddisruptionbudget_test.yaml | 79 + .../tests/default-backend-service_test.yaml | 32 + .../default-backend-serviceaccount_test.yaml | 51 + ingress-nginx/values.yaml | 402 ++ kafka/.helmignore | 25 + kafka/Chart.lock | 9 + kafka/Chart.yaml | 42 + kafka/README.md | 1571 ++++++++ kafka/charts/common/.helmignore | 26 + kafka/charts/common/Chart.yaml | 23 + kafka/charts/common/README.md | 235 ++ kafka/charts/common/templates/_affinities.tpl | 155 + .../charts/common/templates/_capabilities.tpl | 253 ++ .../common/templates/_compatibility.tpl | 46 + kafka/charts/common/templates/_errors.tpl | 85 + kafka/charts/common/templates/_images.tpl | 115 + kafka/charts/common/templates/_ingress.tpl | 73 + kafka/charts/common/templates/_labels.tpl | 46 + kafka/charts/common/templates/_names.tpl | 71 + kafka/charts/common/templates/_resources.tpl | 50 + kafka/charts/common/templates/_secrets.tpl | 192 + kafka/charts/common/templates/_storage.tpl | 21 + kafka/charts/common/templates/_tplvalues.tpl | 52 + kafka/charts/common/templates/_utils.tpl | 77 + kafka/charts/common/templates/_warnings.tpl | 109 + .../templates/validations/_cassandra.tpl | 51 + .../common/templates/validations/_mariadb.tpl | 108 + .../common/templates/validations/_mongodb.tpl | 67 + .../common/templates/validations/_mysql.tpl | 67 + .../templates/validations/_postgresql.tpl | 105 + .../common/templates/validations/_redis.tpl | 48 + .../templates/validations/_validations.tpl | 51 + kafka/charts/common/values.yaml | 8 + kafka/charts/zookeeper/.helmignore | 25 + kafka/charts/zookeeper/Chart.lock | 6 + kafka/charts/zookeeper/Chart.yaml | 29 + kafka/charts/zookeeper/README.md | 599 +++ .../zookeeper/charts/common/.helmignore | 26 + .../charts/zookeeper/charts/common/Chart.yaml | 23 + .../charts/zookeeper/charts/common/README.md | 235 ++ .../charts/common/templates/_affinities.tpl | 155 + .../charts/common/templates/_capabilities.tpl | 253 ++ .../common/templates/_compatibility.tpl | 46 + .../charts/common/templates/_errors.tpl | 85 + .../charts/common/templates/_images.tpl | 115 + .../charts/common/templates/_ingress.tpl | 73 + .../charts/common/templates/_labels.tpl | 46 + .../charts/common/templates/_names.tpl | 71 + .../charts/common/templates/_resources.tpl | 50 + .../charts/common/templates/_secrets.tpl | 192 + .../charts/common/templates/_storage.tpl | 21 + .../charts/common/templates/_tplvalues.tpl | 52 + .../charts/common/templates/_utils.tpl | 77 + .../charts/common/templates/_warnings.tpl | 109 + .../templates/validations/_cassandra.tpl | 51 + .../common/templates/validations/_mariadb.tpl | 108 + .../common/templates/validations/_mongodb.tpl | 67 + .../common/templates/validations/_mysql.tpl | 67 + .../templates/validations/_postgresql.tpl | 105 + .../common/templates/validations/_redis.tpl | 48 + .../templates/validations/_validations.tpl | 51 + .../zookeeper/charts/common/values.yaml | 8 + kafka/charts/zookeeper/templates/NOTES.txt | 81 + kafka/charts/zookeeper/templates/_helpers.tpl | 352 ++ .../charts/zookeeper/templates/configmap.yaml | 20 + .../zookeeper/templates/extra-list.yaml | 9 + .../zookeeper/templates/metrics-svc.yaml | 27 + .../zookeeper/templates/networkpolicy.yaml | 86 + kafka/charts/zookeeper/templates/pdb.yaml | 28 + .../zookeeper/templates/prometheusrule.yaml | 25 + .../templates/scripts-configmap.yaml | 104 + kafka/charts/zookeeper/templates/secrets.yaml | 70 + .../zookeeper/templates/serviceaccount.yaml | 20 + .../zookeeper/templates/servicemonitor.yaml | 57 + .../zookeeper/templates/statefulset.yaml | 573 +++ .../zookeeper/templates/svc-headless.yaml | 40 + kafka/charts/zookeeper/templates/svc.yaml | 72 + .../zookeeper/templates/tls-secrets.yaml | 56 + kafka/charts/zookeeper/values.yaml | 1022 +++++ kafka/templates/NOTES.txt | 338 ++ kafka/templates/_helpers.tpl | 1231 ++++++ kafka/templates/broker/config-secrets.yaml | 25 + kafka/templates/broker/configmap.yaml | 56 + kafka/templates/broker/hpa.yaml | 52 + kafka/templates/broker/pdb.yaml | 30 + kafka/templates/broker/statefulset.yaml | 512 +++ .../templates/broker/svc-external-access.yaml | 75 + kafka/templates/broker/svc-headless.yaml | 45 + kafka/templates/broker/vpa.yaml | 46 + .../controller-eligible/config-secrets.yaml | 25 + .../controller-eligible/configmap.yaml | 55 + kafka/templates/controller-eligible/hpa.yaml | 52 + kafka/templates/controller-eligible/pdb.yaml | 30 + .../controller-eligible/statefulset.yaml | 511 +++ .../svc-external-access.yaml | 77 + .../controller-eligible/svc-headless.yaml | 53 + kafka/templates/controller-eligible/vpa.yaml | 46 + kafka/templates/extra-list.yaml | 9 + kafka/templates/log4j-configmap.yaml | 20 + kafka/templates/metrics/jmx-configmap.yaml | 70 + .../templates/metrics/jmx-servicemonitor.yaml | 49 + kafka/templates/metrics/jmx-svc.yaml | 38 + kafka/templates/metrics/prometheusrule.yaml | 20 + kafka/templates/networkpolicy.yaml | 86 + kafka/templates/provisioning/job.yaml | 291 ++ .../provisioning/serviceaccount.yaml | 17 + kafka/templates/provisioning/tls-secret.yaml | 21 + kafka/templates/rbac/role.yaml | 26 + kafka/templates/rbac/rolebinding.yaml | 25 + kafka/templates/rbac/serviceaccount.yaml | 19 + kafka/templates/scripts-configmap.yaml | 400 ++ kafka/templates/secrets.yaml | 132 + kafka/templates/svc.yaml | 76 + kafka/templates/tls-secret.yaml | 93 + kafka/templates/vault-setup.yaml | 43 + kafka/values.yaml | 2695 ++++++++++++++ livekit/livekit-egress/.helmignore | 23 + livekit/livekit-egress/Chart.yaml | 9 + livekit/livekit-egress/templates/NOTES.txt | 5 + livekit/livekit-egress/templates/_helpers.tpl | 62 + .../livekit-egress/templates/configmap.yaml | 7 + .../livekit-egress/templates/deployment.yaml | 72 + livekit/livekit-egress/templates/hpa.yaml | 58 + .../templates/serviceaccount.yaml | 12 + livekit/livekit-egress/values.yaml | 52 + livekit/livekit-server/.helmignore | 23 + livekit/livekit-server/Chart.yaml | 9 + livekit/livekit-server/templates/NOTES.txt | 50 + livekit/livekit-server/templates/_helpers.tpl | 73 + .../templates/backendconfig.yaml | 8 + .../livekit-server/templates/configmap.yaml | 7 + .../livekit-server/templates/deployment.yaml | 147 + livekit/livekit-server/templates/hpa.yaml | 44 + livekit/livekit-server/templates/ingress.yaml | 75 + .../templates/ingress_turn.yaml | 22 + livekit/livekit-server/templates/secret.yaml | 10 + livekit/livekit-server/templates/service.yaml | 50 + .../templates/serviceaccount.yaml | 12 + .../templates/servicemonitor.yaml | 20 + .../templates/tests/test-connection.yaml | 21 + .../templates/turnloadbalancer.yaml | 20 + livekit/livekit-server/values.yaml | 177 + nfs-subdir-external-provisioner/Chart.yaml | 13 + nfs-subdir-external-provisioner/README.md | 101 + .../ci/test-values.yaml | 5 + .../templates/_helpers.tpl | 103 + .../templates/clusterrole.yaml | 30 + .../templates/clusterrolebinding.yaml | 16 + .../templates/deployment.yaml | 83 + .../templates/persistentvolume.yaml | 26 + .../templates/persistentvolumeclaim.yaml | 19 + .../templates/poddisruptionbudget.yaml | 13 + .../templates/podsecuritypolicy.yaml | 29 + .../templates/role.yaml | 18 + .../templates/rolebinding.yaml | 16 + .../templates/serviceaccount.yaml | 12 + .../templates/storageclass.yaml | 33 + nfs-subdir-external-provisioner/values.yaml | 114 + postgresql-ha/.helmignore | 25 + postgresql-ha/Chart.lock | 6 + postgresql-ha/Chart.yaml | 42 + postgresql-ha/README.md | 1224 ++++++ postgresql-ha/charts/common/.helmignore | 24 + postgresql-ha/charts/common/Chart.yaml | 23 + postgresql-ha/charts/common/README.md | 235 ++ .../charts/common/templates/_affinities.tpl | 139 + .../charts/common/templates/_capabilities.tpl | 221 ++ .../common/templates/_compatibility.tpl | 38 + .../charts/common/templates/_errors.tpl | 28 + .../charts/common/templates/_images.tpl | 109 + .../charts/common/templates/_ingress.tpl | 73 + .../charts/common/templates/_labels.tpl | 46 + .../charts/common/templates/_names.tpl | 71 + .../charts/common/templates/_resources.tpl | 50 + .../charts/common/templates/_secrets.tpl | 182 + .../charts/common/templates/_storage.tpl | 22 + .../charts/common/templates/_tplvalues.tpl | 38 + .../charts/common/templates/_utils.tpl | 77 + .../charts/common/templates/_warnings.tpl | 109 + .../templates/validations/_cassandra.tpl | 77 + .../common/templates/validations/_mariadb.tpl | 108 + .../common/templates/validations/_mongodb.tpl | 113 + .../common/templates/validations/_mysql.tpl | 108 + .../templates/validations/_postgresql.tpl | 134 + .../common/templates/validations/_redis.tpl | 81 + .../templates/validations/_validations.tpl | 51 + postgresql-ha/charts/common/values.yaml | 8 + postgresql-ha/templates/NOTES.txt | 109 + postgresql-ha/templates/_helpers.tpl | 736 ++++ postgresql-ha/templates/backup/cronjob.yaml | 118 + postgresql-ha/templates/backup/pvc.yaml | 34 + postgresql-ha/templates/extra-list.yaml | 9 + postgresql-ha/templates/ldap-secrets.yaml | 19 + .../templates/metrics-configmap.yaml | 18 + postgresql-ha/templates/pgpool/configmap.yaml | 22 + .../pgpool/custom-users-secrets.yaml | 23 + .../templates/pgpool/deployment.yaml | 449 +++ .../pgpool/initdb-scripts-configmap.yaml | 21 + .../templates/pgpool/networkpolicy.yaml | 88 + postgresql-ha/templates/pgpool/pdb.yaml | 30 + postgresql-ha/templates/pgpool/secrets.yaml | 22 + postgresql-ha/templates/pgpool/service.yaml | 54 + .../templates/podsecuritypolicy.yaml | 44 + .../templates/postgresql/configmap.yaml | 30 + .../postgresql/extended-configmap.yaml | 20 + .../postgresql/hooks-scripts-configmap.yaml | 136 + .../postgresql/initdb-scripts-configmap.yaml | 19 + .../templates/postgresql/metrics-service.yaml | 47 + .../templates/postgresql/networkpolicy.yaml | 80 + postgresql-ha/templates/postgresql/pdb.yaml | 28 + .../templates/postgresql/secrets.yaml | 24 + .../postgresql/service-headless.yaml | 28 + .../templates/postgresql/service-witness.yaml | 29 + .../templates/postgresql/service.yaml | 31 + .../templates/postgresql/servicemonitor.yaml | 49 + .../templates/postgresql/statefulset.yaml | 678 ++++ .../templates/postgresql/witness-pdb.yaml | 30 + .../postgresql/witness-statefulset.yaml | 629 ++++ postgresql-ha/templates/role.yaml | 27 + postgresql-ha/templates/rolebinding.yaml | 24 + postgresql-ha/templates/serviceaccount.yaml | 18 + postgresql-ha/templates/tls-secrets.yaml | 29 + postgresql-ha/templates/vault-setup.yaml | 43 + postgresql-ha/values.yaml | 2277 ++++++++++++ postgresql/.helmignore | 25 + postgresql/Chart.lock | 6 + postgresql/Chart.yaml | 38 + postgresql/README.md | 1142 ++++++ postgresql/charts/common/.helmignore | 26 + postgresql/charts/common/Chart.yaml | 23 + postgresql/charts/common/README.md | 235 ++ .../charts/common/templates/_affinities.tpl | 155 + .../charts/common/templates/_capabilities.tpl | 253 ++ .../common/templates/_compatibility.tpl | 46 + .../charts/common/templates/_errors.tpl | 85 + .../charts/common/templates/_images.tpl | 115 + .../charts/common/templates/_ingress.tpl | 73 + .../charts/common/templates/_labels.tpl | 46 + postgresql/charts/common/templates/_names.tpl | 71 + .../charts/common/templates/_resources.tpl | 50 + .../charts/common/templates/_secrets.tpl | 192 + .../charts/common/templates/_storage.tpl | 21 + .../charts/common/templates/_tplvalues.tpl | 52 + postgresql/charts/common/templates/_utils.tpl | 77 + .../charts/common/templates/_warnings.tpl | 109 + .../templates/validations/_cassandra.tpl | 51 + .../common/templates/validations/_mariadb.tpl | 108 + .../common/templates/validations/_mongodb.tpl | 67 + .../common/templates/validations/_mysql.tpl | 67 + .../templates/validations/_postgresql.tpl | 105 + .../common/templates/validations/_redis.tpl | 48 + .../templates/validations/_validations.tpl | 51 + postgresql/charts/common/values.yaml | 8 + postgresql/templates/NOTES.txt | 121 + postgresql/templates/_helpers.tpl | 455 +++ postgresql/templates/backup/cronjob.yaml | 138 + .../templates/backup/networkpolicy.yaml | 32 + postgresql/templates/backup/pvc.yaml | 34 + postgresql/templates/extra-list.yaml | 9 + postgresql/templates/primary/configmap.yaml | 26 + .../templates/primary/extended-configmap.yaml | 20 + .../primary/initialization-configmap.yaml | 17 + .../templates/primary/metrics-configmap.yaml | 18 + postgresql/templates/primary/metrics-svc.yaml | 31 + .../templates/primary/networkpolicy.yaml | 78 + postgresql/templates/primary/pdb.yaml | 29 + .../primary/preinitialization-configmap.yaml | 17 + .../templates/primary/servicemonitor.yaml | 46 + postgresql/templates/primary/statefulset.yaml | 705 ++++ .../templates/primary/svc-headless.yaml | 31 + postgresql/templates/primary/svc.yaml | 58 + postgresql/templates/prometheusrule.yaml | 22 + postgresql/templates/psp.yaml | 42 + .../templates/read/extended-configmap.yaml | 20 + .../templates/read/metrics-configmap.yaml | 18 + postgresql/templates/read/metrics-svc.yaml | 31 + postgresql/templates/read/networkpolicy.yaml | 80 + postgresql/templates/read/pdb.yaml | 29 + postgresql/templates/read/servicemonitor.yaml | 46 + postgresql/templates/read/statefulset.yaml | 588 +++ postgresql/templates/read/svc-headless.yaml | 33 + postgresql/templates/read/svc.yaml | 60 + postgresql/templates/role.yaml | 32 + postgresql/templates/rolebinding.yaml | 24 + postgresql/templates/secrets.yaml | 120 + postgresql/templates/serviceaccount.yaml | 18 + postgresql/templates/tls-secrets.yaml | 30 + postgresql/templates/update-password/job.yaml | 235 ++ .../templates/update-password/new-secret.yaml | 32 + .../update-password/previous-secret.yaml | 32 + postgresql/values.schema.json | 156 + postgresql/values.yaml | 1951 ++++++++++ redis/.helmignore | 25 + redis/CHANGELOG.md | 2041 ++++++++++ redis/Chart.lock | 6 + redis/Chart.yaml | 40 + redis/README.md | 1336 +++++++ redis/img/redis-cluster-topology.png | Bin 0 -> 11448 bytes redis/img/redis-topology.png | Bin 0 -> 9709 bytes redis/templates/NOTES.txt | 216 ++ redis/templates/_helpers.tpl | 338 ++ redis/templates/configmap.yaml | 101 + redis/templates/extra-list.yaml | 9 + redis/templates/headless-svc.yaml | 38 + redis/templates/health-configmap.yaml | 204 + redis/templates/master/application.yaml | 565 +++ redis/templates/master/pdb.yaml | 27 + redis/templates/master/psp.yaml | 47 + redis/templates/master/pvc.yaml | 33 + redis/templates/master/service.yaml | 62 + redis/templates/master/serviceaccount.yaml | 18 + redis/templates/metrics-svc.yaml | 44 + redis/templates/networkpolicy.yaml | 108 + redis/templates/podmonitor.yaml | 81 + redis/templates/prometheusrule.yaml | 23 + redis/templates/replicas/application.yaml | 580 +++ redis/templates/replicas/hpa.yaml | 49 + redis/templates/replicas/pdb.yaml | 28 + redis/templates/replicas/service.yaml | 59 + redis/templates/replicas/serviceaccount.yaml | 18 + redis/templates/role.yaml | 34 + redis/templates/rolebinding.yaml | 23 + redis/templates/scripts-configmap.yaml | 870 +++++ redis/templates/secret-svcbind.yaml | 37 + redis/templates/secret.yaml | 25 + redis/templates/sentinel/hpa.yaml | 49 + redis/templates/sentinel/node-services.yaml | 67 + redis/templates/sentinel/pdb.yaml | 27 + redis/templates/sentinel/ports-configmap.yaml | 102 + redis/templates/sentinel/service.yaml | 163 + redis/templates/sentinel/statefulset.yaml | 893 +++++ redis/templates/serviceaccount.yaml | 18 + redis/templates/servicemonitor.yaml | 82 + redis/templates/svc-external.yaml | 67 + redis/templates/tls-secret.yaml | 31 + redis/values.schema.json | 3297 +++++++++++++++++ redis/values.yaml | 2338 ++++++++++++ vault-secrets-operator/.helmignore | 23 + vault-secrets-operator/Chart.yaml | 9 + .../crds/secrets.hashicorp.com_hcpauths.yaml | 110 + ...ets.hashicorp.com_hcpvaultsecretsapps.yaml | 318 ++ ...s.hashicorp.com_secrettransformations.yaml | 121 + ...ecrets.hashicorp.com_vaultauthglobals.yaml | 334 ++ .../secrets.hashicorp.com_vaultauths.yaml | 398 ++ ...ecrets.hashicorp.com_vaultconnections.yaml | 87 + ...ets.hashicorp.com_vaultdynamicsecrets.yaml | 410 ++ ...secrets.hashicorp.com_vaultpkisecrets.yaml | 386 ++ ...rets.hashicorp.com_vaultstaticsecrets.yaml | 313 ++ vault-secrets-operator/templates/_helpers.tpl | 347 ++ .../templates/cluster-role-binding.yaml | 21 + .../clusterrole-aggregated-editor.yaml | 21 + .../clusterrole-aggregated-viewer.yaml | 21 + .../default-transit-auth-method.yaml | 28 + .../templates/default-vault-auth-method.yaml | 31 + .../templates/default-vault-connection.yaml | 30 + .../templates/deployment.yaml | 231 ++ .../templates/hcpauth_editor_role.yaml | 36 + .../templates/hcpauth_viewer_role.yaml | 32 + .../hcpvaultsecretsapp_editor_role.yaml | 36 + .../hcpvaultsecretsapp_viewer_role.yaml | 32 + .../templates/hook-upgrade-crds.yaml | 118 + .../templates/leader-election-rbac.yaml | 62 + .../templates/manager-config.yaml | 26 + .../templates/metrics-reader-rbac.yaml | 17 + .../templates/metrics-service.yaml | 21 + .../templates/prometheus-servicemonitor.yaml | 38 + .../templates/proxy-rbac.yaml | 41 + vault-secrets-operator/templates/role.yaml | 126 + .../secrettransformation_editor_role.yaml | 36 + .../secrettransformation_viewer_role.yaml | 32 + .../templates/tests/test-runner.yaml | 23 + .../templates/vaultauth_editor_role.yaml | 36 + .../templates/vaultauth_viewer_role.yaml | 32 + .../vaultauthglobal_editor_role.yaml | 36 + .../vaultauthglobal_viewer_role.yaml | 32 + .../vaultconnection_editor_role.yaml | 36 + .../vaultconnection_viewer_role.yaml | 32 + .../vaultdynamicsecret_editor_role.yaml | 36 + .../vaultdynamicsecret_viewer_role.yaml | 32 + .../templates/vaultpkisecret_editor_role.yaml | 36 + .../templates/vaultpkisecret_viewer_role.yaml | 32 + .../vaultstaticsecret_editor_role.yaml | 36 + .../vaultstaticsecret_viewer_role.yaml | 32 + vault-secrets-operator/values.yaml | 884 +++++ vault/.helmignore | 29 + vault/Chart.yaml | 19 + vault/Makefile | 101 + vault/README.md | 43 + vault/templates/NOTES.txt | 14 + vault/templates/_helpers.tpl | 1114 ++++++ vault/templates/csi-agent-configmap.yaml | 34 + vault/templates/csi-clusterrole.yaml | 23 + vault/templates/csi-clusterrolebinding.yaml | 24 + vault/templates/csi-daemonset.yaml | 162 + vault/templates/csi-role.yaml | 32 + vault/templates/csi-rolebinding.yaml | 25 + vault/templates/csi-serviceaccount.yaml | 21 + vault/templates/injector-certs-secret.yaml | 19 + vault/templates/injector-clusterrole.yaml | 30 + .../injector-clusterrolebinding.yaml | 24 + vault/templates/injector-deployment.yaml | 179 + .../templates/injector-disruptionbudget.yaml | 25 + .../templates/injector-mutating-webhook.yaml | 45 + vault/templates/injector-network-policy.yaml | 29 + vault/templates/injector-psp-role.yaml | 25 + vault/templates/injector-psp-rolebinding.yaml | 26 + vault/templates/injector-psp.yaml | 51 + vault/templates/injector-role.yaml | 34 + vault/templates/injector-rolebinding.yaml | 27 + vault/templates/injector-service.yaml | 27 + vault/templates/injector-serviceaccount.yaml | 18 + .../templates/prometheus-prometheusrules.yaml | 31 + .../templates/prometheus-servicemonitor.yaml | 58 + .../templates/server-clusterrolebinding.yaml | 29 + vault/templates/server-config-configmap.yaml | 31 + vault/templates/server-discovery-role.yaml | 26 + .../server-discovery-rolebinding.yaml | 34 + vault/templates/server-disruptionbudget.yaml | 31 + vault/templates/server-ha-active-service.yaml | 64 + .../templates/server-ha-standby-service.yaml | 63 + vault/templates/server-headless-service.yaml | 47 + vault/templates/server-ingress.yaml | 69 + vault/templates/server-network-policy.yaml | 24 + vault/templates/server-psp-role.yaml | 25 + vault/templates/server-psp-rolebinding.yaml | 26 + vault/templates/server-psp.yaml | 54 + vault/templates/server-route.yaml | 39 + vault/templates/server-service.yaml | 59 + .../server-serviceaccount-secret.yaml | 21 + vault/templates/server-serviceaccount.yaml | 22 + vault/templates/server-statefulset.yaml | 232 ++ vault/templates/tests/server-test.yaml | 60 + vault/templates/ui-service.yaml | 50 + vault/test/README.md | 55 + vault/test/acceptance/_helpers.bash | 163 + vault/test/acceptance/csi-test/nginx.yaml | 30 + .../vault-kv-secretproviderclass.yaml | 16 + .../test/acceptance/csi-test/vault-policy.hcl | 6 + vault/test/acceptance/csi.bats | 83 + vault/test/acceptance/helm-test.bats | 27 + .../acceptance/injector-cross-namespace.bats | 72 + .../acceptance/injector-leader-elector.bats | 52 + .../bootstrap-cross-namespace.sh | 49 + .../acceptance/injector-test/bootstrap.sh | 49 + vault/test/acceptance/injector-test/job.yaml | 42 + .../injector-test/pg-deployment.yaml | 72 + .../injector-test/pgdump-policy.hcl | 6 + vault/test/acceptance/injector.bats | 58 + vault/test/acceptance/server-annotations.bats | 46 + vault/test/acceptance/server-dev.bats | 64 + .../acceptance/server-ha-enterprise-dr.bats | 166 + .../acceptance/server-ha-enterprise-perf.bats | 164 + vault/test/acceptance/server-ha-raft.bats | 121 + vault/test/acceptance/server-ha.bats | 121 + vault/test/acceptance/server-telemetry.bats | 73 + .../server-test/annotations-overrides.yaml | 12 + .../acceptance/server-test/vault-server.yaml | 23 + .../server-test/vault-telemetry.yaml | 16 + vault/test/acceptance/server.bats | 109 + vault/test/chart/_helpers.bash | 27 + vault/test/chart/verifier.bats | 94 + vault/test/docker/Test.dockerfile | 58 + vault/test/kind/config.yaml | 23 + vault/test/terraform/main.tf | 75 + vault/test/terraform/outputs.tf | 10 + vault/test/terraform/variables.tf | 31 + vault/test/unit/_helpers.bash | 7 + vault/test/unit/csi-agent-configmap.bats | 64 + vault/test/unit/csi-clusterrole.bats | 33 + vault/test/unit/csi-clusterrolebinding.bats | 64 + vault/test/unit/csi-daemonset.bats | 903 +++++ vault/test/unit/csi-role.bats | 58 + vault/test/unit/csi-rolebinding.bats | 41 + vault/test/unit/csi-serviceaccount.bats | 94 + vault/test/unit/injector-clusterrole.bats | 52 + .../unit/injector-clusterrolebinding.bats | 41 + vault/test/unit/injector-deployment.bats | 1128 ++++++ .../test/unit/injector-disruptionbudget.bats | 62 + vault/test/unit/injector-leader-elector.bats | 225 ++ .../test/unit/injector-mutating-webhook.bats | 334 ++ vault/test/unit/injector-psp-role.bats | 56 + vault/test/unit/injector-psp-rolebinding.bats | 56 + vault/test/unit/injector-psp.bats | 70 + vault/test/unit/injector-service.bats | 83 + vault/test/unit/injector-serviceaccount.bats | 49 + .../test/unit/prometheus-prometheusrules.bats | 68 + .../test/unit/prometheus-servicemonitor.bats | 167 + vault/test/unit/schema.bats | 46 + .../test/unit/server-clusterrolebinding.bats | 90 + vault/test/unit/server-configmap.bats | 254 ++ vault/test/unit/server-dev-statefulset.bats | 461 +++ vault/test/unit/server-discovery-role.bats | 60 + .../unit/server-discovery-rolebinding.bats | 60 + vault/test/unit/server-ha-active-service.bats | 290 ++ .../test/unit/server-ha-disruptionbudget.bats | 130 + .../test/unit/server-ha-standby-service.bats | 312 ++ vault/test/unit/server-ha-statefulset.bats | 791 ++++ vault/test/unit/server-headless-service.bats | 98 + vault/test/unit/server-ingress.bats | 273 ++ vault/test/unit/server-network-policy.bats | 46 + vault/test/unit/server-psp-role.bats | 130 + vault/test/unit/server-psp-rolebinding.bats | 130 + vault/test/unit/server-psp.bats | 285 ++ vault/test/unit/server-route.bats | 202 + vault/test/unit/server-service.bats | 511 +++ .../unit/server-serviceaccount-secret.bats | 77 + vault/test/unit/server-serviceaccount.bats | 148 + vault/test/unit/server-statefulset.bats | 2076 +++++++++++ vault/test/unit/server-test.bats | 305 ++ vault/test/unit/ui-service.bats | 432 +++ vault/values.openshift.yaml | 24 + vault/values.schema.json | 1315 +++++++ vault/values.yaml | 1344 +++++++ 1401 files changed, 139327 insertions(+) create mode 100644 README.md create mode 100644 argo-infra-apps/cassandra.yaml create mode 100644 argo-infra-apps/elasticsearch.yaml create mode 100644 argo-infra-apps/grafana.yaml create mode 100644 argo-infra-apps/ingress-nginx.yaml create mode 100644 argo-infra-apps/kafka.yaml create mode 100644 argo-infra-apps/livekit-egress.yaml create mode 100644 argo-infra-apps/livekit-server.yaml create mode 100644 argo-infra-apps/nfs-subdir-external-provisione.yaml create mode 100644 argo-infra-apps/postgres.yaml create mode 100644 argo-infra-apps/postgresql-ha.yaml create mode 100644 argo-infra-apps/redis.yaml create mode 100644 argo-infra-apps/vault-secrets-operator.yaml create mode 100644 argo-infra-apps/vault.yaml create mode 100644 caddy/.helmignore create mode 100644 caddy/Chart.yaml create mode 100644 caddy/LICENSE create mode 100644 caddy/README.md create mode 100644 caddy/templates/NOTES.txt create mode 100644 caddy/templates/_helpers.tpl create mode 100644 caddy/templates/configmap.yaml create mode 100644 caddy/templates/deployment.yaml create mode 100644 caddy/templates/hpa.yaml create mode 100644 caddy/templates/ingress.yaml create mode 100644 caddy/templates/service.yaml create mode 100644 caddy/templates/serviceaccount.yaml create mode 100644 caddy/templates/tests/test-connection.yaml create mode 100644 caddy/values.yaml create mode 100644 cassandra/.helmignore create mode 100644 cassandra/Chart.lock create mode 100644 cassandra/Chart.yaml create mode 100644 cassandra/README.md create mode 100644 cassandra/charts/common/.helmignore create mode 100644 cassandra/charts/common/Chart.yaml create mode 100644 cassandra/charts/common/README.md create mode 100644 cassandra/charts/common/templates/_affinities.tpl create mode 100644 cassandra/charts/common/templates/_capabilities.tpl create mode 100644 cassandra/charts/common/templates/_compatibility.tpl create mode 100644 cassandra/charts/common/templates/_errors.tpl create mode 100644 cassandra/charts/common/templates/_images.tpl create mode 100644 cassandra/charts/common/templates/_ingress.tpl create mode 100644 cassandra/charts/common/templates/_labels.tpl create mode 100644 cassandra/charts/common/templates/_names.tpl create mode 100644 cassandra/charts/common/templates/_resources.tpl create mode 100644 cassandra/charts/common/templates/_secrets.tpl create mode 100644 cassandra/charts/common/templates/_storage.tpl create mode 100644 cassandra/charts/common/templates/_tplvalues.tpl create mode 100644 cassandra/charts/common/templates/_utils.tpl create mode 100644 cassandra/charts/common/templates/_warnings.tpl create mode 100644 cassandra/charts/common/templates/validations/_cassandra.tpl create mode 100644 cassandra/charts/common/templates/validations/_mariadb.tpl create mode 100644 cassandra/charts/common/templates/validations/_mongodb.tpl create mode 100644 cassandra/charts/common/templates/validations/_mysql.tpl create mode 100644 cassandra/charts/common/templates/validations/_postgresql.tpl create mode 100644 cassandra/charts/common/templates/validations/_redis.tpl create mode 100644 cassandra/charts/common/templates/validations/_validations.tpl create mode 100644 cassandra/charts/common/values.yaml create mode 100644 cassandra/templates/NOTES.txt create mode 100644 cassandra/templates/_helpers.tpl create mode 100644 cassandra/templates/cassandra-secret.yaml create mode 100644 cassandra/templates/extra-list.yaml create mode 100644 cassandra/templates/headless-svc.yaml create mode 100644 cassandra/templates/init_cm.yaml create mode 100644 cassandra/templates/initdb-configmap.yaml create mode 100644 cassandra/templates/metrics-configmap.yaml create mode 100644 cassandra/templates/networkpolicy.yaml create mode 100644 cassandra/templates/pdb.yaml create mode 100644 cassandra/templates/service.yaml create mode 100644 cassandra/templates/serviceaccount.yaml create mode 100644 cassandra/templates/servicemonitor.yaml create mode 100644 cassandra/templates/statefulset.yaml create mode 100644 cassandra/templates/tls-secret.yaml create mode 100644 cassandra/values.yaml create mode 100644 compose/ansible.cfg create mode 100644 compose/custom_inventory/group_vars/all/all.yaml create mode 100755 compose/custom_inventory/host_vars/cw-sya-reg-001/common.yml create mode 100644 compose/custom_inventory/host_vars/cw-sya-reg-001/files/ssl/docker.crt create mode 100644 compose/custom_inventory/host_vars/cw-sya-reg-001/files/ssl/docker.key create mode 100755 compose/custom_inventory/hosts create mode 100644 compose/inventory/hosts create mode 100644 compose/playbooks/ca_server/README.md create mode 100644 compose/playbooks/ca_server/ansible.cfg create mode 100644 compose/playbooks/ca_server/defaults/main.yml create mode 100644 compose/playbooks/ca_server/handlers/main.yml create mode 100644 compose/playbooks/ca_server/inventory/hosts create mode 100644 compose/playbooks/ca_server/main.yml create mode 100644 compose/playbooks/ca_server/roles/ca_install/README.md create mode 100644 compose/playbooks/ca_server/roles/ca_install/handlers/main.yml create mode 100644 compose/playbooks/ca_server/roles/ca_install/tasks/configure_ca.yml create mode 100644 compose/playbooks/ca_server/roles/ca_install/tasks/create_cert.yml create mode 100644 compose/playbooks/ca_server/roles/ca_install/tasks/main.yml create mode 100644 compose/playbooks/ca_server/roles/ca_install/templates/template.cnf.j2 create mode 100644 compose/playbooks/ca_server/roles/ca_install/vars/main.yml create mode 100644 compose/playbooks/ca_server/tasks/check_os_version.yml create mode 100644 compose/playbooks/ca_server/vars/base_conf.yml create mode 100644 compose/playbooks/ca_server/vars/secret.yml create mode 100644 compose/playbooks/dns_server/README.md create mode 100644 compose/playbooks/dns_server/ansible.cfg create mode 100644 compose/playbooks/dns_server/defaults/main.yml create mode 100644 compose/playbooks/dns_server/handlers/main.yml create mode 100644 compose/playbooks/dns_server/inventory/hosts create mode 100644 compose/playbooks/dns_server/main.yml create mode 100644 compose/playbooks/dns_server/roles/bind_install/README.md create mode 100644 compose/playbooks/dns_server/roles/bind_install/handlers/main.yml create mode 100644 compose/playbooks/dns_server/roles/bind_install/tasks/configure_bind.yml create mode 100644 compose/playbooks/dns_server/roles/bind_install/tasks/install_bind.yml create mode 100644 compose/playbooks/dns_server/roles/bind_install/tasks/main.yml create mode 100644 compose/playbooks/dns_server/roles/bind_install/templates/dns_zone_local.j2 create mode 100644 compose/playbooks/dns_server/roles/bind_install/templates/named.conf.local.j2 create mode 100644 compose/playbooks/dns_server/roles/bind_install/templates/named.conf.options.j2 create mode 100644 compose/playbooks/dns_server/roles/bind_install/vars/main.yml create mode 100644 compose/playbooks/dns_server/tasks/check_os_version.yml create mode 100644 compose/playbooks/dns_server/vars/base_conf.yml create mode 100644 compose/playbooks/dns_server/vars/dns_zone.yml create mode 100644 compose/playbooks/infra-base_admin.yml create mode 100644 compose/playbooks/infra-docker-registry.yml create mode 100644 compose/playbooks/keycloak_server/README.md create mode 100644 compose/playbooks/keycloak_server/ansible.cfg create mode 100644 compose/playbooks/keycloak_server/defaults/main.yml create mode 100644 compose/playbooks/keycloak_server/handlers/main.yml create mode 100644 compose/playbooks/keycloak_server/inventory/hosts create mode 100644 compose/playbooks/keycloak_server/main.yml create mode 100644 compose/playbooks/keycloak_server/roles/docker_install/README.md create mode 100644 compose/playbooks/keycloak_server/roles/docker_install/handlers/main.yml create mode 100644 compose/playbooks/keycloak_server/roles/docker_install/tasks/configure_docker.yml create mode 100644 compose/playbooks/keycloak_server/roles/docker_install/tasks/install_docker.yml create mode 100644 compose/playbooks/keycloak_server/roles/docker_install/tasks/main.yml create mode 100644 compose/playbooks/keycloak_server/roles/docker_install/templates/daemon.json.j2 create mode 100644 compose/playbooks/keycloak_server/roles/docker_install/vars/main.yml create mode 100644 compose/playbooks/keycloak_server/roles/keycloak_install_docker/README.md create mode 100644 compose/playbooks/keycloak_server/roles/keycloak_install_docker/handlers/main.yml create mode 100644 compose/playbooks/keycloak_server/roles/keycloak_install_docker/tasks/install_keycloak.yml create mode 100644 compose/playbooks/keycloak_server/roles/keycloak_install_docker/tasks/main.yml create mode 100644 compose/playbooks/keycloak_server/roles/keycloak_install_docker/templates/compose.yml.j2 create mode 100644 compose/playbooks/keycloak_server/roles/keycloak_install_docker/vars/main.yml create mode 100644 compose/playbooks/keycloak_server/tasks/check_os_version.yml create mode 100644 compose/playbooks/keycloak_server/vars/base_conf.yml create mode 100644 compose/playbooks/keycloak_server/vars/secret.yml create mode 100644 compose/playbooks/openldap_server/README.md create mode 100644 compose/playbooks/openldap_server/ansible.cfg create mode 100644 compose/playbooks/openldap_server/defaults/main.yml create mode 100644 compose/playbooks/openldap_server/handlers/main.yml create mode 100644 compose/playbooks/openldap_server/inventory/hosts create mode 100644 compose/playbooks/openldap_server/main.yml create mode 100644 compose/playbooks/openldap_server/roles/docker_install/README.md create mode 100644 compose/playbooks/openldap_server/roles/docker_install/handlers/main.yml create mode 100644 compose/playbooks/openldap_server/roles/docker_install/tasks/configure_docker.yml create mode 100644 compose/playbooks/openldap_server/roles/docker_install/tasks/install_docker.yml create mode 100644 compose/playbooks/openldap_server/roles/docker_install/tasks/main.yml create mode 100644 compose/playbooks/openldap_server/roles/docker_install/templates/daemon.json.j2 create mode 100644 compose/playbooks/openldap_server/roles/docker_install/vars/main.yml create mode 100644 compose/playbooks/openldap_server/roles/openldap_install_docker/README.md create mode 100644 compose/playbooks/openldap_server/roles/openldap_install_docker/files/cert/RootCA.crt create mode 100644 compose/playbooks/openldap_server/roles/openldap_install_docker/handlers/main.yml create mode 100644 compose/playbooks/openldap_server/roles/openldap_install_docker/tasks/install_openldap.yml create mode 100644 compose/playbooks/openldap_server/roles/openldap_install_docker/tasks/main.yml create mode 100644 compose/playbooks/openldap_server/roles/openldap_install_docker/templates/compose.yml.j2 create mode 100644 compose/playbooks/openldap_server/roles/openldap_install_docker/templates/haproxy.cfg.j2 create mode 100644 compose/playbooks/openldap_server/roles/openldap_install_docker/vars/main.yml create mode 100644 compose/playbooks/openldap_server/tasks/check_os_version.yml create mode 100644 compose/playbooks/openldap_server/vars/base_conf.yml create mode 100644 compose/playbooks/openldap_server/vars/secret.yml create mode 100644 compose/playbooks/prep_ubuntu/README.md create mode 100644 compose/playbooks/prep_ubuntu/ansible.cfg create mode 100644 compose/playbooks/prep_ubuntu/defaults/main.yml create mode 100644 compose/playbooks/prep_ubuntu/handlers/main.yml create mode 100644 compose/playbooks/prep_ubuntu/inventory/hosts create mode 100644 compose/playbooks/prep_ubuntu/main.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/README.md create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/handlers/main.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/add_admin_user.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/apt_config.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/cert_ca_import.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/dnsmasq_config.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/enable_services.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/fstrim-timer_enable.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/history_config.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/hosts_file_config.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/install-pkg.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/journald_config.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/logrotate_config.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/main.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/profile_config.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/set_root_pass.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/ssh_conf.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/swap_config.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/sysctl_config.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/time_sync_config.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/timezone_config.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/ufw_conf.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/update_packages.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/apt/apt.conf.d/10-no-check-valid-until.j2 create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/chrony.j2 create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/dhcp/dhclient.conf.j2 create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/dnsmasq.d/local-cache.j2 create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/logrotate.j2 create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/ssh/sshd_config.j2 create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/systemd/journald.j2 create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/README.md create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/handlers/main.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/tasks/configure_docker.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/tasks/install_docker.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/tasks/main.yml create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/templates/daemon.json.j2 create mode 100644 compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/vars/main.yml create mode 100644 compose/playbooks/prep_ubuntu/tasks/check_os_version.yml create mode 100644 compose/playbooks/prep_ubuntu/tasks/reboot.yml create mode 100644 compose/playbooks/prep_ubuntu/vars/base_conf.yml create mode 100644 compose/playbooks/prep_ubuntu/vars/secret.yml create mode 100644 compose/playbooks/s3_server/README.md create mode 100644 compose/playbooks/s3_server/ansible.cfg create mode 100644 compose/playbooks/s3_server/defaults/main.yml create mode 100644 compose/playbooks/s3_server/handlers/main.yml create mode 100644 compose/playbooks/s3_server/inventory/hosts create mode 100644 compose/playbooks/s3_server/main.yml create mode 100644 compose/playbooks/s3_server/roles/minio_install/README.md create mode 100644 compose/playbooks/s3_server/roles/minio_install/handlers/main.yml create mode 100644 compose/playbooks/s3_server/roles/minio_install/tasks/configure_minio.yml create mode 100644 compose/playbooks/s3_server/roles/minio_install/tasks/disk_layout.yml create mode 100644 compose/playbooks/s3_server/roles/minio_install/tasks/install_minio.yml create mode 100644 compose/playbooks/s3_server/roles/minio_install/tasks/main.yml create mode 100644 compose/playbooks/s3_server/roles/minio_install/templates/minio.j2 create mode 100644 compose/playbooks/s3_server/roles/minio_install/vars/main.yml create mode 100644 compose/playbooks/s3_server/tasks/check_os_version.yml create mode 100644 compose/playbooks/s3_server/vars/base_conf.yml create mode 100644 compose/playbooks/s3_server/vars/secret.yml create mode 100755 compose/roles/infra-common/tasks/main.yml create mode 100644 compose/roles/infra-container-registry/defaults/main.yml create mode 100644 compose/roles/infra-container-registry/handlers/main.yml create mode 100644 compose/roles/infra-container-registry/tasks/configure.yml create mode 100644 compose/roles/infra-container-registry/tasks/deploy.yml create mode 100644 compose/roles/infra-container-registry/tasks/install.yml create mode 100644 compose/roles/infra-container-registry/tasks/main.yml create mode 100644 compose/roles/infra-container-registry/templates/docker-compose.yml.j2 create mode 100644 elasticsearch/.helmignore create mode 100644 elasticsearch/Chart.yaml create mode 100644 elasticsearch/Makefile create mode 100644 elasticsearch/README.md create mode 100644 elasticsearch/examples/config/Makefile create mode 100644 elasticsearch/examples/config/README.md create mode 100644 elasticsearch/examples/config/test/goss.yaml create mode 100644 elasticsearch/examples/config/values.yaml create mode 100644 elasticsearch/examples/config/watcher_encryption_key create mode 100644 elasticsearch/examples/default/Makefile create mode 100644 elasticsearch/examples/default/README.md create mode 100644 elasticsearch/examples/default/rolling_upgrade.sh create mode 100644 elasticsearch/examples/default/test/goss.yaml create mode 100644 elasticsearch/examples/docker-for-mac/Makefile create mode 100644 elasticsearch/examples/docker-for-mac/README.md create mode 100644 elasticsearch/examples/docker-for-mac/values.yaml create mode 100644 elasticsearch/examples/kubernetes-kind/Makefile create mode 100644 elasticsearch/examples/kubernetes-kind/README.md create mode 100644 elasticsearch/examples/kubernetes-kind/values-local-path.yaml create mode 100644 elasticsearch/examples/kubernetes-kind/values.yaml create mode 100644 elasticsearch/examples/microk8s/Makefile create mode 100644 elasticsearch/examples/microk8s/README.md create mode 100644 elasticsearch/examples/microk8s/values.yaml create mode 100644 elasticsearch/examples/migration/Makefile create mode 100644 elasticsearch/examples/migration/README.md create mode 100644 elasticsearch/examples/migration/client.yaml create mode 100644 elasticsearch/examples/migration/data.yaml create mode 100644 elasticsearch/examples/migration/master.yaml create mode 100644 elasticsearch/examples/minikube/Makefile create mode 100644 elasticsearch/examples/minikube/README.md create mode 100644 elasticsearch/examples/minikube/values.yaml create mode 100644 elasticsearch/examples/multi/Makefile create mode 100644 elasticsearch/examples/multi/README.md create mode 100644 elasticsearch/examples/multi/client.yaml create mode 100644 elasticsearch/examples/multi/data.yaml create mode 100644 elasticsearch/examples/multi/master.yaml create mode 100644 elasticsearch/examples/multi/test/goss.yaml create mode 100644 elasticsearch/examples/networkpolicy/Makefile create mode 100644 elasticsearch/examples/networkpolicy/values.yaml create mode 100644 elasticsearch/examples/openshift/Makefile create mode 100644 elasticsearch/examples/openshift/README.md create mode 100644 elasticsearch/examples/openshift/test/goss.yaml create mode 100644 elasticsearch/examples/openshift/values.yaml create mode 100644 elasticsearch/examples/security/Makefile create mode 100644 elasticsearch/examples/security/README.md create mode 100644 elasticsearch/examples/security/test/goss.yaml create mode 100644 elasticsearch/examples/security/values.yaml create mode 100644 elasticsearch/examples/upgrade/Makefile create mode 100644 elasticsearch/examples/upgrade/README.md create mode 100644 elasticsearch/examples/upgrade/test/goss.yaml create mode 100644 elasticsearch/examples/upgrade/values.yaml create mode 100644 elasticsearch/templates/NOTES.txt create mode 100644 elasticsearch/templates/_helpers.tpl create mode 100644 elasticsearch/templates/configmap.yaml create mode 100644 elasticsearch/templates/index_configmap.yaml create mode 100644 elasticsearch/templates/ingress.yaml create mode 100644 elasticsearch/templates/networkpolicy.yaml create mode 100644 elasticsearch/templates/poddisruptionbudget.yaml create mode 100644 elasticsearch/templates/podsecuritypolicy.yaml create mode 100644 elasticsearch/templates/role.yaml create mode 100644 elasticsearch/templates/rolebinding.yaml create mode 100644 elasticsearch/templates/secret-cert.yaml create mode 100644 elasticsearch/templates/secret.yaml create mode 100644 elasticsearch/templates/service.yaml create mode 100644 elasticsearch/templates/serviceaccount.yaml create mode 100644 elasticsearch/templates/statefulset.yaml create mode 100644 elasticsearch/templates/test/test-elasticsearch-health.yaml create mode 100644 elasticsearch/values.yaml create mode 100644 grafana/Chart.yaml create mode 100644 grafana/charts/alloy-1.0.2.tgz create mode 100644 grafana/charts/feature-annotation-autodiscovery/.helmignore create mode 100644 grafana/charts/feature-annotation-autodiscovery/Chart.lock create mode 100644 grafana/charts/feature-annotation-autodiscovery/Chart.yaml create mode 100644 grafana/charts/feature-annotation-autodiscovery/Makefile create mode 100644 grafana/charts/feature-annotation-autodiscovery/README.md create mode 100644 grafana/charts/feature-annotation-autodiscovery/README.md.gotmpl create mode 100644 grafana/charts/feature-annotation-autodiscovery/templates/_helpers.tpl create mode 100644 grafana/charts/feature-annotation-autodiscovery/templates/_module.alloy.tpl create mode 100644 grafana/charts/feature-annotation-autodiscovery/templates/_notes.tpl create mode 100644 grafana/charts/feature-annotation-autodiscovery/templates/_pods.alloy.tpl create mode 100644 grafana/charts/feature-annotation-autodiscovery/templates/_services.alloy.tpl create mode 100644 grafana/charts/feature-annotation-autodiscovery/templates/_validation.tpl create mode 100644 grafana/charts/feature-annotation-autodiscovery/templates/configmap.yaml create mode 100644 grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/.gitkeep create mode 100644 grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/default_test.yaml.snap create mode 100644 grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/namespaced_test.yaml.snap create mode 100644 grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/pods_only_test.yaml.snap create mode 100644 grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/prometheus_annotation_test.yaml.snap create mode 100644 grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/selectors_test.yaml.snap create mode 100644 grafana/charts/feature-annotation-autodiscovery/tests/default_test.yaml create mode 100644 grafana/charts/feature-annotation-autodiscovery/tests/namespaced_test.yaml create mode 100644 grafana/charts/feature-annotation-autodiscovery/tests/pods_only_test.yaml create mode 100644 grafana/charts/feature-annotation-autodiscovery/tests/prometheus_annotation_test.yaml create mode 100644 grafana/charts/feature-annotation-autodiscovery/tests/selectors_test.yaml create mode 100644 grafana/charts/feature-annotation-autodiscovery/values.schema.json create mode 100644 grafana/charts/feature-annotation-autodiscovery/values.yaml create mode 100644 grafana/charts/feature-application-observability/.helmignore create mode 100644 grafana/charts/feature-application-observability/Chart.lock create mode 100644 grafana/charts/feature-application-observability/Chart.yaml create mode 100644 grafana/charts/feature-application-observability/Makefile create mode 100644 grafana/charts/feature-application-observability/README.md create mode 100644 grafana/charts/feature-application-observability/README.md.gotmpl create mode 100644 grafana/charts/feature-application-observability/schema-mods/types-and-enums.json create mode 100644 grafana/charts/feature-application-observability/templates/_connector_host_info.tpl create mode 100644 grafana/charts/feature-application-observability/templates/_connector_span_logs.tpl create mode 100644 grafana/charts/feature-application-observability/templates/_connector_span_metrics.tpl create mode 100644 grafana/charts/feature-application-observability/templates/_helpers.tpl create mode 100644 grafana/charts/feature-application-observability/templates/_module.alloy.tpl create mode 100644 grafana/charts/feature-application-observability/templates/_notes.tpl create mode 100644 grafana/charts/feature-application-observability/templates/_pipeline.tpl create mode 100644 grafana/charts/feature-application-observability/templates/_processor_batch.tpl create mode 100644 grafana/charts/feature-application-observability/templates/_processor_filter.tpl create mode 100644 grafana/charts/feature-application-observability/templates/_processor_interval.tpl create mode 100644 grafana/charts/feature-application-observability/templates/_processor_k8sattributes.tpl create mode 100644 grafana/charts/feature-application-observability/templates/_processor_memory_limiter.tpl create mode 100644 grafana/charts/feature-application-observability/templates/_processor_resourcedetection.tpl create mode 100644 grafana/charts/feature-application-observability/templates/_processor_transform.tpl create mode 100644 grafana/charts/feature-application-observability/templates/_receiver_jaeger.tpl create mode 100644 grafana/charts/feature-application-observability/templates/_receiver_otlp.tpl create mode 100644 grafana/charts/feature-application-observability/templates/_receiver_zipkin.tpl create mode 100644 grafana/charts/feature-application-observability/templates/_validation.tpl create mode 100644 grafana/charts/feature-application-observability/templates/configmap.yaml create mode 100644 grafana/charts/feature-application-observability/tests/__snapshot__/.gitkeep create mode 100644 grafana/charts/feature-application-observability/tests/__snapshot__/default_test.yaml.snap create mode 100644 grafana/charts/feature-application-observability/tests/__snapshot__/interval_test.yaml.snap create mode 100644 grafana/charts/feature-application-observability/tests/__snapshot__/jaeger_test.yaml.snap create mode 100644 grafana/charts/feature-application-observability/tests/__snapshot__/memorylimiter_test.yaml.snap create mode 100644 grafana/charts/feature-application-observability/tests/__snapshot__/resourcedetection_test.yaml.snap create mode 100644 grafana/charts/feature-application-observability/tests/__snapshot__/spanlogs_test.yaml.snap create mode 100644 grafana/charts/feature-application-observability/tests/__snapshot__/spanmetrics_test.yaml.snap create mode 100644 grafana/charts/feature-application-observability/tests/default_test.yaml create mode 100644 grafana/charts/feature-application-observability/tests/interval_test.yaml create mode 100644 grafana/charts/feature-application-observability/tests/jaeger_test.yaml create mode 100644 grafana/charts/feature-application-observability/tests/memorylimiter_test.yaml create mode 100644 grafana/charts/feature-application-observability/tests/resourcedetection_test.yaml create mode 100644 grafana/charts/feature-application-observability/tests/spanlogs_test.yaml create mode 100644 grafana/charts/feature-application-observability/tests/spanmetrics_test.yaml create mode 100644 grafana/charts/feature-application-observability/tests/validation_test.yaml create mode 100644 grafana/charts/feature-application-observability/values.schema.json create mode 100644 grafana/charts/feature-application-observability/values.yaml create mode 100644 grafana/charts/feature-auto-instrumentation/.helmignore create mode 100644 grafana/charts/feature-auto-instrumentation/Chart.lock create mode 100644 grafana/charts/feature-auto-instrumentation/Chart.yaml create mode 100644 grafana/charts/feature-auto-instrumentation/Makefile create mode 100644 grafana/charts/feature-auto-instrumentation/README.md create mode 100644 grafana/charts/feature-auto-instrumentation/README.md.gotmpl create mode 100644 grafana/charts/feature-auto-instrumentation/charts/beyla-1.7.3.tgz create mode 100644 grafana/charts/feature-auto-instrumentation/schema-mods/remote-beyla-config-data.jq create mode 100644 grafana/charts/feature-auto-instrumentation/schema-mods/types-and-enums.json create mode 100644 grafana/charts/feature-auto-instrumentation/templates/_helpers.tpl create mode 100644 grafana/charts/feature-auto-instrumentation/templates/_module.alloy.tpl create mode 100644 grafana/charts/feature-auto-instrumentation/templates/_notes.tpl create mode 100644 grafana/charts/feature-auto-instrumentation/templates/configmap.yaml create mode 100644 grafana/charts/feature-auto-instrumentation/templates/platform_specific/openshift/beyla-scc.yaml create mode 100644 grafana/charts/feature-auto-instrumentation/tests/__snapshot__/.gitkeep create mode 100644 grafana/charts/feature-auto-instrumentation/tests/default_test.yaml create mode 100644 grafana/charts/feature-auto-instrumentation/values.schema.json create mode 100644 grafana/charts/feature-auto-instrumentation/values.yaml create mode 100644 grafana/charts/feature-cluster-events/.helmignore create mode 100644 grafana/charts/feature-cluster-events/Chart.lock create mode 100644 grafana/charts/feature-cluster-events/Chart.yaml create mode 100644 grafana/charts/feature-cluster-events/Makefile create mode 100644 grafana/charts/feature-cluster-events/README.md create mode 100644 grafana/charts/feature-cluster-events/README.md.gotmpl create mode 100644 grafana/charts/feature-cluster-events/templates/_helpers.tpl create mode 100644 grafana/charts/feature-cluster-events/templates/_module.alloy.tpl create mode 100644 grafana/charts/feature-cluster-events/templates/_notes.tpl create mode 100644 grafana/charts/feature-cluster-events/templates/configmap.yaml create mode 100644 grafana/charts/feature-cluster-events/tests/__snapshot__/default_test.yaml.snap create mode 100644 grafana/charts/feature-cluster-events/tests/__snapshot__/extra_processing_stages_test.yaml.snap create mode 100644 grafana/charts/feature-cluster-events/tests/__snapshot__/labels_test.yaml.snap create mode 100644 grafana/charts/feature-cluster-events/tests/__snapshot__/namespace_test.yaml.snap create mode 100644 grafana/charts/feature-cluster-events/tests/__snapshot__/structured_metadata_test.yaml.snap create mode 100644 grafana/charts/feature-cluster-events/tests/default_test.yaml create mode 100644 grafana/charts/feature-cluster-events/tests/extra_processing_stages_test.yaml create mode 100644 grafana/charts/feature-cluster-events/tests/labels_test.yaml create mode 100644 grafana/charts/feature-cluster-events/tests/namespace_test.yaml create mode 100644 grafana/charts/feature-cluster-events/tests/structured_metadata_test.yaml create mode 100644 grafana/charts/feature-cluster-events/values.schema.json create mode 100644 grafana/charts/feature-cluster-events/values.yaml create mode 100644 grafana/charts/feature-cluster-metrics/.ct.yaml create mode 100644 grafana/charts/feature-cluster-metrics/.helmignore create mode 100644 grafana/charts/feature-cluster-metrics/Chart.lock create mode 100644 grafana/charts/feature-cluster-metrics/Chart.yaml create mode 100644 grafana/charts/feature-cluster-metrics/Makefile create mode 100644 grafana/charts/feature-cluster-metrics/README.md create mode 100644 grafana/charts/feature-cluster-metrics/README.md.gotmpl create mode 100644 grafana/charts/feature-cluster-metrics/charts/kepler-0.5.13.tgz create mode 100644 grafana/charts/feature-cluster-metrics/charts/kube-state-metrics-5.32.0.tgz create mode 100644 grafana/charts/feature-cluster-metrics/charts/opencost-1.43.2.tgz create mode 100644 grafana/charts/feature-cluster-metrics/charts/prometheus-node-exporter-4.45.2.tgz create mode 100644 grafana/charts/feature-cluster-metrics/charts/prometheus-windows-exporter-0.10.0.tgz create mode 100644 grafana/charts/feature-cluster-metrics/default-allow-lists/cadvisor.yaml create mode 100644 grafana/charts/feature-cluster-metrics/default-allow-lists/kepler.yaml create mode 100644 grafana/charts/feature-cluster-metrics/default-allow-lists/kube-state-metrics.yaml create mode 100644 grafana/charts/feature-cluster-metrics/default-allow-lists/kubelet.yaml create mode 100644 grafana/charts/feature-cluster-metrics/default-allow-lists/kubelet_probes.yaml create mode 100644 grafana/charts/feature-cluster-metrics/default-allow-lists/kubelet_resource.yaml create mode 100644 grafana/charts/feature-cluster-metrics/default-allow-lists/node-exporter-integration.yaml create mode 100644 grafana/charts/feature-cluster-metrics/default-allow-lists/node-exporter.yaml create mode 100644 grafana/charts/feature-cluster-metrics/default-allow-lists/opencost.yaml create mode 100644 grafana/charts/feature-cluster-metrics/default-allow-lists/windows-exporter.yaml create mode 100644 grafana/charts/feature-cluster-metrics/schema-mods/remove-subchart-fields.jq create mode 100644 grafana/charts/feature-cluster-metrics/schema-mods/types-and-enums.json create mode 100644 grafana/charts/feature-cluster-metrics/templates/_api_server.alloy.tpl create mode 100644 grafana/charts/feature-cluster-metrics/templates/_cadvisor.alloy.tpl create mode 100644 grafana/charts/feature-cluster-metrics/templates/_helpers.tpl create mode 100644 grafana/charts/feature-cluster-metrics/templates/_kepler.alloy.tpl create mode 100644 grafana/charts/feature-cluster-metrics/templates/_kube_controller_manager.alloy.tpl create mode 100644 grafana/charts/feature-cluster-metrics/templates/_kube_dns.alloy.tpl create mode 100644 grafana/charts/feature-cluster-metrics/templates/_kube_proxy.alloy.tpl create mode 100644 grafana/charts/feature-cluster-metrics/templates/_kube_scheduler.alloy.tpl create mode 100644 grafana/charts/feature-cluster-metrics/templates/_kube_state_metrics.alloy.tpl create mode 100644 grafana/charts/feature-cluster-metrics/templates/_kubelet.alloy.tpl create mode 100644 grafana/charts/feature-cluster-metrics/templates/_kubelet_probes.alloy.tpl create mode 100644 grafana/charts/feature-cluster-metrics/templates/_kubelet_resource.alloy.tpl create mode 100644 grafana/charts/feature-cluster-metrics/templates/_module.alloy.tpl create mode 100644 grafana/charts/feature-cluster-metrics/templates/_node_exporter.alloy.tpl create mode 100644 grafana/charts/feature-cluster-metrics/templates/_notes.tpl create mode 100644 grafana/charts/feature-cluster-metrics/templates/_opencost.alloy.tpl create mode 100644 grafana/charts/feature-cluster-metrics/templates/_windows_exporter.alloy.tpl create mode 100644 grafana/charts/feature-cluster-metrics/templates/configmap.yaml create mode 100644 grafana/charts/feature-cluster-metrics/templates/platform_specific/openshift/kepler-scc.yaml create mode 100644 grafana/charts/feature-cluster-metrics/tests/__snapshot__/.gitkeep create mode 100644 grafana/charts/feature-cluster-metrics/tests/__snapshot__/alternative-discovery_test.yaml.snap create mode 100644 grafana/charts/feature-cluster-metrics/tests/__snapshot__/control_plane_test.yaml.snap create mode 100644 grafana/charts/feature-cluster-metrics/tests/__snapshot__/custom_rules_test.yaml.snap create mode 100644 grafana/charts/feature-cluster-metrics/tests/__snapshot__/default_test.yaml.snap create mode 100644 grafana/charts/feature-cluster-metrics/tests/__snapshot__/kepler_test.yaml.snap create mode 100644 grafana/charts/feature-cluster-metrics/tests/__snapshot__/metrics_tuning_test.yaml.snap create mode 100644 grafana/charts/feature-cluster-metrics/tests/__snapshot__/opencost_test.yaml.snap create mode 100644 grafana/charts/feature-cluster-metrics/tests/__snapshot__/openshift_test.yaml.snap create mode 100644 grafana/charts/feature-cluster-metrics/tests/alternative-discovery_test.yaml create mode 100644 grafana/charts/feature-cluster-metrics/tests/control_plane_test.yaml create mode 100644 grafana/charts/feature-cluster-metrics/tests/custom_rules_test.yaml create mode 100644 grafana/charts/feature-cluster-metrics/tests/default_test.yaml create mode 100644 grafana/charts/feature-cluster-metrics/tests/kepler_test.yaml create mode 100644 grafana/charts/feature-cluster-metrics/tests/metrics_tuning_test.yaml create mode 100644 grafana/charts/feature-cluster-metrics/tests/opencost_test.yaml create mode 100644 grafana/charts/feature-cluster-metrics/tests/openshift-kepler-scc_test.yaml create mode 100644 grafana/charts/feature-cluster-metrics/tests/openshift_test.yaml create mode 100644 grafana/charts/feature-cluster-metrics/values.schema.json create mode 100644 grafana/charts/feature-cluster-metrics/values.yaml create mode 100644 grafana/charts/feature-integrations/.helmignore create mode 100644 grafana/charts/feature-integrations/Chart.lock create mode 100644 grafana/charts/feature-integrations/Chart.yaml create mode 100644 grafana/charts/feature-integrations/Makefile create mode 100644 grafana/charts/feature-integrations/README.md create mode 100644 grafana/charts/feature-integrations/README.md.gotmpl create mode 100644 grafana/charts/feature-integrations/default-allow-lists/alloy.yaml create mode 100644 grafana/charts/feature-integrations/default-allow-lists/loki.yaml create mode 100644 grafana/charts/feature-integrations/default-allow-lists/mimir.yaml create mode 100644 grafana/charts/feature-integrations/default-allow-lists/tempo.yaml create mode 100644 grafana/charts/feature-integrations/docs/integrations/.doc_templates/alloy.gotmpl create mode 100644 grafana/charts/feature-integrations/docs/integrations/alloy.md create mode 100644 grafana/charts/feature-integrations/docs/integrations/cert-manager.md create mode 100644 grafana/charts/feature-integrations/docs/integrations/etcd.md create mode 100644 grafana/charts/feature-integrations/docs/integrations/grafana.md create mode 100644 grafana/charts/feature-integrations/docs/integrations/loki.md create mode 100644 grafana/charts/feature-integrations/docs/integrations/mimir.md create mode 100644 grafana/charts/feature-integrations/docs/integrations/mysql.md create mode 100644 grafana/charts/feature-integrations/docs/integrations/tempo.md create mode 100644 grafana/charts/feature-integrations/integrations/alloy-values.yaml create mode 100644 grafana/charts/feature-integrations/integrations/cert-manager-values.yaml create mode 100644 grafana/charts/feature-integrations/integrations/etcd-values.yaml create mode 100644 grafana/charts/feature-integrations/integrations/grafana-values.yaml create mode 100644 grafana/charts/feature-integrations/integrations/loki-values.yaml create mode 100644 grafana/charts/feature-integrations/integrations/mimir-values.yaml create mode 100644 grafana/charts/feature-integrations/integrations/mysql-values.yaml create mode 100644 grafana/charts/feature-integrations/integrations/tempo-values.yaml create mode 100644 grafana/charts/feature-integrations/schema-mods/definitions/alloy-integration.schema.json create mode 100644 grafana/charts/feature-integrations/schema-mods/definitions/cert-manager-integration.schema.json create mode 100644 grafana/charts/feature-integrations/schema-mods/definitions/etcd-integration.schema.json create mode 100644 grafana/charts/feature-integrations/schema-mods/definitions/grafana-integration.schema.json create mode 100644 grafana/charts/feature-integrations/schema-mods/definitions/loki-integration.schema.json create mode 100644 grafana/charts/feature-integrations/schema-mods/definitions/mimir-integration.schema.json create mode 100644 grafana/charts/feature-integrations/schema-mods/definitions/mysql-integration.schema.json create mode 100644 grafana/charts/feature-integrations/schema-mods/definitions/tempo-integration.schema.json create mode 100644 grafana/charts/feature-integrations/schema-mods/integration-list.json create mode 100644 grafana/charts/feature-integrations/schema-mods/label-selectors.json create mode 100644 grafana/charts/feature-integrations/templates/_helpers.tpl create mode 100644 grafana/charts/feature-integrations/templates/_helpers_modules.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_alloy.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_cert-manager.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_etcd.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_grafana.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_grafana_logs.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_grafana_metrics.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_helpers.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_loki.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_loki_logs.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_loki_metrics.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_mimir.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_mimir_logs.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_mimir_metrics.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_mysql.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_mysql_logs.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_mysql_metrics.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_tempo.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_tempo_logs.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_tempo_metrics.tpl create mode 100644 grafana/charts/feature-integrations/templates/_integration_types.tpl create mode 100644 grafana/charts/feature-integrations/templates/_notes.tpl create mode 100644 grafana/charts/feature-integrations/templates/_validation.tpl create mode 100644 grafana/charts/feature-integrations/templates/configmap.yaml create mode 100644 grafana/charts/feature-integrations/templates/mysql-secret.yaml create mode 100644 grafana/charts/feature-integrations/templates/secrets/_helpers.tpl create mode 100644 grafana/charts/feature-integrations/templates/secrets/_secret.alloy.tpl create mode 100644 grafana/charts/feature-integrations/tests/__snapshot__/mysql_metrics_test.yaml.snap create mode 100644 grafana/charts/feature-integrations/tests/alloy_test.yaml create mode 100644 grafana/charts/feature-integrations/tests/cert-manager_test.yaml create mode 100644 grafana/charts/feature-integrations/tests/etcd_test.yaml create mode 100644 grafana/charts/feature-integrations/tests/grafana_logs_test.yaml create mode 100644 grafana/charts/feature-integrations/tests/grafana_metrics_test.yaml create mode 100644 grafana/charts/feature-integrations/tests/loki_logs_test.yaml create mode 100644 grafana/charts/feature-integrations/tests/loki_metrics_test.yaml create mode 100644 grafana/charts/feature-integrations/tests/mimir_logs_test.yaml create mode 100644 grafana/charts/feature-integrations/tests/mimir_metrics_test.yaml create mode 100644 grafana/charts/feature-integrations/tests/mysql_logs_test.yaml create mode 100644 grafana/charts/feature-integrations/tests/mysql_metrics_test.yaml create mode 100644 grafana/charts/feature-integrations/tests/tempo_logs_test.yaml create mode 100644 grafana/charts/feature-integrations/tests/tempo_metrics_test.yaml create mode 100644 grafana/charts/feature-integrations/values.schema.json create mode 100644 grafana/charts/feature-integrations/values.yaml create mode 100644 grafana/charts/feature-node-logs/.helmignore create mode 100644 grafana/charts/feature-node-logs/Chart.lock create mode 100644 grafana/charts/feature-node-logs/Chart.yaml create mode 100644 grafana/charts/feature-node-logs/Makefile create mode 100644 grafana/charts/feature-node-logs/README.md create mode 100644 grafana/charts/feature-node-logs/README.md.gotmpl create mode 100644 grafana/charts/feature-node-logs/templates/_collector_validation.tpl create mode 100644 grafana/charts/feature-node-logs/templates/_helpers.tpl create mode 100644 grafana/charts/feature-node-logs/templates/_module.alloy.tpl create mode 100644 grafana/charts/feature-node-logs/templates/_notes.tpl create mode 100644 grafana/charts/feature-node-logs/templates/configmap.yaml create mode 100644 grafana/charts/feature-node-logs/tests/__snapshot__/.gitkeep create mode 100644 grafana/charts/feature-node-logs/tests/default_test.yaml create mode 100644 grafana/charts/feature-node-logs/tests/filter_units_test.yaml create mode 100644 grafana/charts/feature-node-logs/tests/labels_test.yaml create mode 100644 grafana/charts/feature-node-logs/tests/structured_metadata_test.yaml create mode 100644 grafana/charts/feature-node-logs/values.schema.json create mode 100644 grafana/charts/feature-node-logs/values.yaml create mode 100644 grafana/charts/feature-pod-logs/.helmignore create mode 100644 grafana/charts/feature-pod-logs/Chart.lock create mode 100644 grafana/charts/feature-pod-logs/Chart.yaml create mode 100644 grafana/charts/feature-pod-logs/Makefile create mode 100644 grafana/charts/feature-pod-logs/README.md create mode 100644 grafana/charts/feature-pod-logs/README.md.gotmpl create mode 100644 grafana/charts/feature-pod-logs/schema-mods/types-and-enums.json create mode 100644 grafana/charts/feature-pod-logs/templates/_api.alloy.tpl create mode 100644 grafana/charts/feature-pod-logs/templates/_collector_validation.tpl create mode 100644 grafana/charts/feature-pod-logs/templates/_common_log_processing.alloy.tpl create mode 100644 grafana/charts/feature-pod-logs/templates/_common_pod_discovery.alloy.tpl create mode 100644 grafana/charts/feature-pod-logs/templates/_filelog.alloy.tpl create mode 100644 grafana/charts/feature-pod-logs/templates/_helpers.tpl create mode 100644 grafana/charts/feature-pod-logs/templates/_log_receiver.alloy.tpl create mode 100644 grafana/charts/feature-pod-logs/templates/_module.alloy.tpl create mode 100644 grafana/charts/feature-pod-logs/templates/_notes.tpl create mode 100644 grafana/charts/feature-pod-logs/templates/_volumes.alloy.tpl create mode 100644 grafana/charts/feature-pod-logs/templates/configmap.yaml create mode 100644 grafana/charts/feature-pod-logs/templates/openshift-cluster-log-forwarder.yaml create mode 100644 grafana/charts/feature-pod-logs/tests/__snapshot__/.gitkeep create mode 100644 grafana/charts/feature-pod-logs/tests/__snapshot__/default_test.yaml.snap create mode 100644 grafana/charts/feature-pod-logs/tests/default_test.yaml create mode 100644 grafana/charts/feature-pod-logs/values.schema.json create mode 100644 grafana/charts/feature-pod-logs/values.yaml create mode 100644 grafana/charts/feature-profiling/.helmignore create mode 100644 grafana/charts/feature-profiling/Chart.lock create mode 100644 grafana/charts/feature-profiling/Chart.yaml create mode 100644 grafana/charts/feature-profiling/Makefile create mode 100644 grafana/charts/feature-profiling/README.md create mode 100644 grafana/charts/feature-profiling/README.md.gotmpl create mode 100644 grafana/charts/feature-profiling/schema-mods/types-and-enums.json create mode 100644 grafana/charts/feature-profiling/templates/_ebpf.tpl create mode 100644 grafana/charts/feature-profiling/templates/_helpers.tpl create mode 100644 grafana/charts/feature-profiling/templates/_java.tpl create mode 100644 grafana/charts/feature-profiling/templates/_module.alloy.tpl create mode 100644 grafana/charts/feature-profiling/templates/_notes.tpl create mode 100644 grafana/charts/feature-profiling/templates/_pprof.tpl create mode 100644 grafana/charts/feature-profiling/templates/configmap.yaml create mode 100644 grafana/charts/feature-profiling/tests/__snapshot__/.gitkeep create mode 100644 grafana/charts/feature-profiling/tests/__snapshot__/ebpf_test.yaml.snap create mode 100644 grafana/charts/feature-profiling/tests/__snapshot__/java_test.yaml.snap create mode 100644 grafana/charts/feature-profiling/tests/__snapshot__/pprof_test.yaml.snap create mode 100644 grafana/charts/feature-profiling/tests/ebpf_test.yaml create mode 100644 grafana/charts/feature-profiling/tests/java_test.yaml create mode 100644 grafana/charts/feature-profiling/tests/pprof_test.yaml create mode 100644 grafana/charts/feature-profiling/values.schema.json create mode 100644 grafana/charts/feature-profiling/values.yaml create mode 100644 grafana/charts/feature-prometheus-operator-objects/.ct.yaml create mode 100644 grafana/charts/feature-prometheus-operator-objects/.helmignore create mode 100644 grafana/charts/feature-prometheus-operator-objects/Chart.lock create mode 100644 grafana/charts/feature-prometheus-operator-objects/Chart.yaml create mode 100644 grafana/charts/feature-prometheus-operator-objects/Makefile create mode 100644 grafana/charts/feature-prometheus-operator-objects/README.md create mode 100644 grafana/charts/feature-prometheus-operator-objects/README.md.gotmpl create mode 100644 grafana/charts/feature-prometheus-operator-objects/charts/prometheus-operator-crds-19.1.0.tgz create mode 100644 grafana/charts/feature-prometheus-operator-objects/templates/_helpers.tpl create mode 100644 grafana/charts/feature-prometheus-operator-objects/templates/_module.alloy.tpl create mode 100644 grafana/charts/feature-prometheus-operator-objects/templates/_notes.tpl create mode 100644 grafana/charts/feature-prometheus-operator-objects/templates/_pod_monitors.alloy.tpl create mode 100644 grafana/charts/feature-prometheus-operator-objects/templates/_probes.alloy.tpl create mode 100644 grafana/charts/feature-prometheus-operator-objects/templates/_service_monitors.alloy.tpl create mode 100644 grafana/charts/feature-prometheus-operator-objects/templates/_validations.tpl create mode 100644 grafana/charts/feature-prometheus-operator-objects/templates/configmap.yaml create mode 100644 grafana/charts/feature-prometheus-operator-objects/tests/__snapshot__/default_test.yaml.snap create mode 100644 grafana/charts/feature-prometheus-operator-objects/tests/__snapshot__/labels_and_expressions_test.yaml.snap create mode 100644 grafana/charts/feature-prometheus-operator-objects/tests/default_test.yaml create mode 100644 grafana/charts/feature-prometheus-operator-objects/tests/labels_and_expressions_test.yaml create mode 100644 grafana/charts/feature-prometheus-operator-objects/values.schema.json create mode 100644 grafana/charts/feature-prometheus-operator-objects/values.yaml create mode 100644 grafana/destinations/loki-values.yaml create mode 100644 grafana/destinations/otlp-values.yaml create mode 100644 grafana/destinations/prometheus-values.yaml create mode 100644 grafana/destinations/pyroscope-values.yaml create mode 100644 grafana/templates/NOTES.txt create mode 100644 grafana/templates/_helpers.tpl create mode 100644 grafana/templates/_platform_validations.tpl create mode 100644 grafana/templates/_validations.tpl create mode 100644 grafana/templates/alloy-config.yaml create mode 100644 grafana/templates/alloy-modules-configmaps.yaml create mode 100644 grafana/templates/beyla-config.yaml create mode 100644 grafana/templates/collectors/_collector_common.tpl create mode 100644 grafana/templates/collectors/_collector_extraConfig.tpl create mode 100644 grafana/templates/collectors/_collector_helpers.tpl create mode 100644 grafana/templates/collectors/_collector_notes.tpl create mode 100644 grafana/templates/collectors/_collector_remoteConfig.tpl create mode 100644 grafana/templates/collectors/_collector_validations.tpl create mode 100644 grafana/templates/destination_secret.yaml create mode 100644 grafana/templates/destinations/_config.alloy.tpl create mode 100644 grafana/templates/destinations/_destination_helpers.tpl create mode 100644 grafana/templates/destinations/_destination_loki.tpl create mode 100644 grafana/templates/destinations/_destination_otlp.tpl create mode 100644 grafana/templates/destinations/_destination_prometheus.tpl create mode 100644 grafana/templates/destinations/_destination_pyroscope.tpl create mode 100644 grafana/templates/destinations/_destination_types.tpl create mode 100644 grafana/templates/destinations/_destination_validations.tpl create mode 100644 grafana/templates/extra-objects.yaml create mode 100644 grafana/templates/features/_feature_annotation_autodiscovery.tpl create mode 100644 grafana/templates/features/_feature_application_observability.tpl create mode 100644 grafana/templates/features/_feature_auto_instrumentation.tpl create mode 100644 grafana/templates/features/_feature_cluster_events.tpl create mode 100644 grafana/templates/features/_feature_cluster_metrics.tpl create mode 100644 grafana/templates/features/_feature_helpers.tpl create mode 100644 grafana/templates/features/_feature_integrations.tpl create mode 100644 grafana/templates/features/_feature_node_logs.tpl create mode 100644 grafana/templates/features/_feature_pod_logs.tpl create mode 100644 grafana/templates/features/_feature_profiling.tpl create mode 100644 grafana/templates/features/_feature_prometheus_operator_obejcts.tpl create mode 100644 grafana/templates/features/_feature_self_reporting.tpl create mode 100644 grafana/templates/platform_specific/openshift/alloy-logs-scc.yaml create mode 100644 grafana/templates/platform_specific/openshift/alloy-metrics-scc.yaml create mode 100644 grafana/templates/platform_specific/openshift/alloy-profiles-scc.yaml create mode 100644 grafana/templates/platform_specific/openshift/alloy-receiver-scc.yaml create mode 100644 grafana/templates/platform_specific/openshift/alloy-singleton-scc.yaml create mode 100644 grafana/templates/receiver-service.yaml create mode 100644 grafana/templates/remote_config_secret.yaml create mode 100644 grafana/templates/secrets/_helpers.tpl create mode 100644 grafana/templates/secrets/_secret.alloy.tpl create mode 100644 grafana/templates/secrets/test/secrets.yaml create mode 100644 grafana/templates/test/helpers.yaml create mode 100644 grafana/templates/validations.yaml create mode 100644 grafana/values.yaml create mode 100644 ingress-nginx/.helmignore create mode 100644 ingress-nginx/Chart.yaml create mode 100644 ingress-nginx/OWNERS create mode 100644 ingress-nginx/README.md create mode 100644 ingress-nginx/README.md.gotmpl create mode 100644 ingress-nginx/changelog/helm-chart-2.10.0.md create mode 100644 ingress-nginx/changelog/helm-chart-2.11.0.md create mode 100644 ingress-nginx/changelog/helm-chart-2.11.1.md create mode 100644 ingress-nginx/changelog/helm-chart-2.11.2.md create mode 100644 ingress-nginx/changelog/helm-chart-2.11.3.md create mode 100644 ingress-nginx/changelog/helm-chart-2.12.0.md create mode 100644 ingress-nginx/changelog/helm-chart-2.12.1.md create mode 100644 ingress-nginx/changelog/helm-chart-2.13.0.md create mode 100644 ingress-nginx/changelog/helm-chart-2.14.0.md create mode 100644 ingress-nginx/changelog/helm-chart-2.15.0.md create mode 100644 ingress-nginx/changelog/helm-chart-2.16.0.md create mode 100644 ingress-nginx/changelog/helm-chart-2.9.0.md create mode 100644 ingress-nginx/changelog/helm-chart-2.9.1.md create mode 100644 ingress-nginx/changelog/helm-chart-3.0.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.10.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.10.1.md create mode 100644 ingress-nginx/changelog/helm-chart-3.11.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.11.1.md create mode 100644 ingress-nginx/changelog/helm-chart-3.12.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.13.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.14.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.15.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.15.1.md create mode 100644 ingress-nginx/changelog/helm-chart-3.16.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.16.1.md create mode 100644 ingress-nginx/changelog/helm-chart-3.17.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.18.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.19.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.20.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.20.1.md create mode 100644 ingress-nginx/changelog/helm-chart-3.21.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.22.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.23.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.24.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.25.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.26.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.27.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.28.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.29.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.3.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.3.1.md create mode 100644 ingress-nginx/changelog/helm-chart-3.30.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.31.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.32.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.33.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.34.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.4.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.5.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.5.1.md create mode 100644 ingress-nginx/changelog/helm-chart-3.6.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.7.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.7.1.md create mode 100644 ingress-nginx/changelog/helm-chart-3.8.0.md create mode 100644 ingress-nginx/changelog/helm-chart-3.9.0.md create mode 100644 ingress-nginx/changelog/helm-chart-4.0.1.md create mode 100644 ingress-nginx/changelog/helm-chart-4.0.10.md create mode 100644 ingress-nginx/changelog/helm-chart-4.0.11.md create mode 100644 ingress-nginx/changelog/helm-chart-4.0.12.md create mode 100644 ingress-nginx/changelog/helm-chart-4.0.13.md create mode 100644 ingress-nginx/changelog/helm-chart-4.0.14.md create mode 100644 ingress-nginx/changelog/helm-chart-4.0.15.md create mode 100644 ingress-nginx/changelog/helm-chart-4.0.18.md create mode 100644 ingress-nginx/changelog/helm-chart-4.0.2.md create mode 100644 ingress-nginx/changelog/helm-chart-4.0.3.md create mode 100644 ingress-nginx/changelog/helm-chart-4.0.5.md create mode 100644 ingress-nginx/changelog/helm-chart-4.0.6.md create mode 100644 ingress-nginx/changelog/helm-chart-4.0.7.md create mode 100644 ingress-nginx/changelog/helm-chart-4.0.9.md create mode 100644 ingress-nginx/changelog/helm-chart-4.1.0.md create mode 100644 ingress-nginx/changelog/helm-chart-4.1.2.md create mode 100644 ingress-nginx/changelog/helm-chart-4.10.0.md create mode 100644 ingress-nginx/changelog/helm-chart-4.10.1.md create mode 100644 ingress-nginx/changelog/helm-chart-4.10.2.md create mode 100644 ingress-nginx/changelog/helm-chart-4.10.3.md create mode 100644 ingress-nginx/changelog/helm-chart-4.10.4.md create mode 100644 ingress-nginx/changelog/helm-chart-4.11.0.md create mode 100644 ingress-nginx/changelog/helm-chart-4.11.1.md create mode 100644 ingress-nginx/changelog/helm-chart-4.11.2.md create mode 100644 ingress-nginx/changelog/helm-chart-4.12.0-beta.0.md create mode 100644 ingress-nginx/changelog/helm-chart-4.12.0.md create mode 100644 ingress-nginx/changelog/helm-chart-4.12.1.md create mode 100644 ingress-nginx/changelog/helm-chart-4.12.2.md create mode 100644 ingress-nginx/changelog/helm-chart-4.2.0.md create mode 100644 ingress-nginx/changelog/helm-chart-4.2.1.md create mode 100644 ingress-nginx/changelog/helm-chart-4.3.0.md create mode 100644 ingress-nginx/changelog/helm-chart-4.4.0.md create mode 100644 ingress-nginx/changelog/helm-chart-4.5.2.md create mode 100644 ingress-nginx/changelog/helm-chart-4.6.0.md create mode 100644 ingress-nginx/changelog/helm-chart-4.6.1.md create mode 100644 ingress-nginx/changelog/helm-chart-4.7.0.md create mode 100644 ingress-nginx/changelog/helm-chart-4.7.1.md create mode 100644 ingress-nginx/changelog/helm-chart-4.7.2.md create mode 100644 ingress-nginx/changelog/helm-chart-4.8.0-beta.0.md create mode 100644 ingress-nginx/changelog/helm-chart-4.8.0.md create mode 100644 ingress-nginx/changelog/helm-chart-4.8.1.md create mode 100644 ingress-nginx/changelog/helm-chart-4.8.2.md create mode 100644 ingress-nginx/changelog/helm-chart-4.8.3.md create mode 100644 ingress-nginx/changelog/helm-chart-4.9.0.md create mode 100644 ingress-nginx/changelog/helm-chart-4.9.1.md create mode 100644 ingress-nginx/changelog/helm-chart.md.gotmpl create mode 100644 ingress-nginx/ci/admission-webhooks-cert-manager-values.yaml create mode 100644 ingress-nginx/ci/controller-configmap-addheaders-values.yaml create mode 100644 ingress-nginx/ci/controller-configmap-proxyheaders-values.yaml create mode 100644 ingress-nginx/ci/controller-configmap-values.yaml create mode 100644 ingress-nginx/ci/controller-daemonset-metrics-values.yaml create mode 100644 ingress-nginx/ci/controller-daemonset-podannotations-values.yaml create mode 100644 ingress-nginx/ci/controller-daemonset-values.yaml create mode 100644 ingress-nginx/ci/controller-deployment-metrics-values.yaml create mode 100644 ingress-nginx/ci/controller-deployment-podannotations-values.yaml create mode 100644 ingress-nginx/ci/controller-deployment-values.yaml create mode 100644 ingress-nginx/ci/controller-hpa-values.yaml create mode 100644 ingress-nginx/ci/controller-ingressclass-values.yaml create mode 100644 ingress-nginx/ci/controller-service-internal-values.yaml create mode 100644 ingress-nginx/ci/controller-service-values.yaml create mode 100644 ingress-nginx/templates/NOTES.txt create mode 100644 ingress-nginx/templates/_helpers.tpl create mode 100644 ingress-nginx/templates/_params.tpl create mode 100644 ingress-nginx/templates/admission-webhooks/cert-manager.yaml create mode 100644 ingress-nginx/templates/admission-webhooks/job-patch/clusterrole.yaml create mode 100644 ingress-nginx/templates/admission-webhooks/job-patch/clusterrolebinding.yaml create mode 100644 ingress-nginx/templates/admission-webhooks/job-patch/job-createSecret.yaml create mode 100644 ingress-nginx/templates/admission-webhooks/job-patch/job-patchWebhook.yaml create mode 100644 ingress-nginx/templates/admission-webhooks/job-patch/networkpolicy.yaml create mode 100644 ingress-nginx/templates/admission-webhooks/job-patch/role.yaml create mode 100644 ingress-nginx/templates/admission-webhooks/job-patch/rolebinding.yaml create mode 100644 ingress-nginx/templates/admission-webhooks/job-patch/serviceaccount.yaml create mode 100644 ingress-nginx/templates/admission-webhooks/validating-webhook.yaml create mode 100644 ingress-nginx/templates/clusterrole.yaml create mode 100644 ingress-nginx/templates/clusterrolebinding.yaml create mode 100644 ingress-nginx/templates/controller-configmap-addheaders.yaml create mode 100644 ingress-nginx/templates/controller-configmap-proxyheaders.yaml create mode 100644 ingress-nginx/templates/controller-configmap-tcp.yaml create mode 100644 ingress-nginx/templates/controller-configmap-udp.yaml create mode 100644 ingress-nginx/templates/controller-configmap.yaml create mode 100644 ingress-nginx/templates/controller-daemonset.yaml create mode 100644 ingress-nginx/templates/controller-deployment.yaml create mode 100644 ingress-nginx/templates/controller-hpa.yaml create mode 100644 ingress-nginx/templates/controller-ingressclass-aliases.yaml create mode 100644 ingress-nginx/templates/controller-ingressclass.yaml create mode 100644 ingress-nginx/templates/controller-keda.yaml create mode 100644 ingress-nginx/templates/controller-networkpolicy.yaml create mode 100644 ingress-nginx/templates/controller-poddisruptionbudget.yaml create mode 100644 ingress-nginx/templates/controller-prometheusrule.yaml create mode 100644 ingress-nginx/templates/controller-role.yaml create mode 100644 ingress-nginx/templates/controller-rolebinding.yaml create mode 100644 ingress-nginx/templates/controller-secret.yaml create mode 100644 ingress-nginx/templates/controller-service-internal.yaml create mode 100644 ingress-nginx/templates/controller-service-metrics.yaml create mode 100644 ingress-nginx/templates/controller-service-webhook.yaml create mode 100644 ingress-nginx/templates/controller-service.yaml create mode 100644 ingress-nginx/templates/controller-serviceaccount.yaml create mode 100644 ingress-nginx/templates/controller-servicemonitor.yaml create mode 100644 ingress-nginx/templates/default-backend-deployment.yaml create mode 100644 ingress-nginx/templates/default-backend-extra-configmaps.yaml create mode 100644 ingress-nginx/templates/default-backend-hpa.yaml create mode 100644 ingress-nginx/templates/default-backend-networkpolicy.yaml create mode 100644 ingress-nginx/templates/default-backend-poddisruptionbudget.yaml create mode 100644 ingress-nginx/templates/default-backend-service.yaml create mode 100644 ingress-nginx/templates/default-backend-serviceaccount.yaml create mode 100644 ingress-nginx/templates/service_additional.yaml create mode 100644 ingress-nginx/tests/admission-webhooks/job-patch/clusterrole_test.yaml create mode 100644 ingress-nginx/tests/admission-webhooks/job-patch/clusterrolebinding_test.yaml create mode 100644 ingress-nginx/tests/admission-webhooks/job-patch/role_test.yaml create mode 100644 ingress-nginx/tests/admission-webhooks/job-patch/rolebinding_test.yaml create mode 100644 ingress-nginx/tests/admission-webhooks/job-patch/serviceaccount_test.yaml create mode 100644 ingress-nginx/tests/admission-webhooks/validating-webhook_test.yaml create mode 100644 ingress-nginx/tests/controller-configmap-addheaders_test.yaml create mode 100644 ingress-nginx/tests/controller-configmap-proxyheaders_test.yaml create mode 100644 ingress-nginx/tests/controller-configmap_test.yaml create mode 100644 ingress-nginx/tests/controller-daemonset_test.yaml create mode 100644 ingress-nginx/tests/controller-deployment_test.yaml create mode 100644 ingress-nginx/tests/controller-hpa_test.yaml create mode 100644 ingress-nginx/tests/controller-ingressclass-aliases_test.yaml create mode 100644 ingress-nginx/tests/controller-ingressclass_test.yaml create mode 100644 ingress-nginx/tests/controller-keda_test.yaml create mode 100644 ingress-nginx/tests/controller-networkpolicy_test.yaml create mode 100644 ingress-nginx/tests/controller-poddisruptionbudget_test.yaml create mode 100644 ingress-nginx/tests/controller-prometheusrule_test.yaml create mode 100644 ingress-nginx/tests/controller-service-internal_test.yaml create mode 100644 ingress-nginx/tests/controller-service-metrics_test.yaml create mode 100644 ingress-nginx/tests/controller-service-webhook_test.yaml create mode 100644 ingress-nginx/tests/controller-service_test.yaml create mode 100644 ingress-nginx/tests/controller-serviceaccount_test.yaml create mode 100644 ingress-nginx/tests/controller-servicemonitor_test.yaml create mode 100644 ingress-nginx/tests/default-backend-deployment_test.yaml create mode 100644 ingress-nginx/tests/default-backend-extra-configmaps_test.yaml create mode 100644 ingress-nginx/tests/default-backend-poddisruptionbudget_test.yaml create mode 100644 ingress-nginx/tests/default-backend-service_test.yaml create mode 100644 ingress-nginx/tests/default-backend-serviceaccount_test.yaml create mode 100644 ingress-nginx/values.yaml create mode 100644 kafka/.helmignore create mode 100644 kafka/Chart.lock create mode 100644 kafka/Chart.yaml create mode 100644 kafka/README.md create mode 100644 kafka/charts/common/.helmignore create mode 100644 kafka/charts/common/Chart.yaml create mode 100644 kafka/charts/common/README.md create mode 100644 kafka/charts/common/templates/_affinities.tpl create mode 100644 kafka/charts/common/templates/_capabilities.tpl create mode 100644 kafka/charts/common/templates/_compatibility.tpl create mode 100644 kafka/charts/common/templates/_errors.tpl create mode 100644 kafka/charts/common/templates/_images.tpl create mode 100644 kafka/charts/common/templates/_ingress.tpl create mode 100644 kafka/charts/common/templates/_labels.tpl create mode 100644 kafka/charts/common/templates/_names.tpl create mode 100644 kafka/charts/common/templates/_resources.tpl create mode 100644 kafka/charts/common/templates/_secrets.tpl create mode 100644 kafka/charts/common/templates/_storage.tpl create mode 100644 kafka/charts/common/templates/_tplvalues.tpl create mode 100644 kafka/charts/common/templates/_utils.tpl create mode 100644 kafka/charts/common/templates/_warnings.tpl create mode 100644 kafka/charts/common/templates/validations/_cassandra.tpl create mode 100644 kafka/charts/common/templates/validations/_mariadb.tpl create mode 100644 kafka/charts/common/templates/validations/_mongodb.tpl create mode 100644 kafka/charts/common/templates/validations/_mysql.tpl create mode 100644 kafka/charts/common/templates/validations/_postgresql.tpl create mode 100644 kafka/charts/common/templates/validations/_redis.tpl create mode 100644 kafka/charts/common/templates/validations/_validations.tpl create mode 100644 kafka/charts/common/values.yaml create mode 100644 kafka/charts/zookeeper/.helmignore create mode 100644 kafka/charts/zookeeper/Chart.lock create mode 100644 kafka/charts/zookeeper/Chart.yaml create mode 100644 kafka/charts/zookeeper/README.md create mode 100644 kafka/charts/zookeeper/charts/common/.helmignore create mode 100644 kafka/charts/zookeeper/charts/common/Chart.yaml create mode 100644 kafka/charts/zookeeper/charts/common/README.md create mode 100644 kafka/charts/zookeeper/charts/common/templates/_affinities.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/_capabilities.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/_compatibility.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/_errors.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/_images.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/_ingress.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/_labels.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/_names.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/_resources.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/_secrets.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/_storage.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/_tplvalues.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/_utils.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/_warnings.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/validations/_cassandra.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/validations/_mariadb.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/validations/_mongodb.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/validations/_mysql.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/validations/_postgresql.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/validations/_redis.tpl create mode 100644 kafka/charts/zookeeper/charts/common/templates/validations/_validations.tpl create mode 100644 kafka/charts/zookeeper/charts/common/values.yaml create mode 100644 kafka/charts/zookeeper/templates/NOTES.txt create mode 100644 kafka/charts/zookeeper/templates/_helpers.tpl create mode 100644 kafka/charts/zookeeper/templates/configmap.yaml create mode 100644 kafka/charts/zookeeper/templates/extra-list.yaml create mode 100644 kafka/charts/zookeeper/templates/metrics-svc.yaml create mode 100644 kafka/charts/zookeeper/templates/networkpolicy.yaml create mode 100644 kafka/charts/zookeeper/templates/pdb.yaml create mode 100644 kafka/charts/zookeeper/templates/prometheusrule.yaml create mode 100644 kafka/charts/zookeeper/templates/scripts-configmap.yaml create mode 100644 kafka/charts/zookeeper/templates/secrets.yaml create mode 100644 kafka/charts/zookeeper/templates/serviceaccount.yaml create mode 100644 kafka/charts/zookeeper/templates/servicemonitor.yaml create mode 100644 kafka/charts/zookeeper/templates/statefulset.yaml create mode 100644 kafka/charts/zookeeper/templates/svc-headless.yaml create mode 100644 kafka/charts/zookeeper/templates/svc.yaml create mode 100644 kafka/charts/zookeeper/templates/tls-secrets.yaml create mode 100644 kafka/charts/zookeeper/values.yaml create mode 100644 kafka/templates/NOTES.txt create mode 100644 kafka/templates/_helpers.tpl create mode 100644 kafka/templates/broker/config-secrets.yaml create mode 100644 kafka/templates/broker/configmap.yaml create mode 100644 kafka/templates/broker/hpa.yaml create mode 100644 kafka/templates/broker/pdb.yaml create mode 100644 kafka/templates/broker/statefulset.yaml create mode 100644 kafka/templates/broker/svc-external-access.yaml create mode 100644 kafka/templates/broker/svc-headless.yaml create mode 100644 kafka/templates/broker/vpa.yaml create mode 100644 kafka/templates/controller-eligible/config-secrets.yaml create mode 100644 kafka/templates/controller-eligible/configmap.yaml create mode 100644 kafka/templates/controller-eligible/hpa.yaml create mode 100644 kafka/templates/controller-eligible/pdb.yaml create mode 100644 kafka/templates/controller-eligible/statefulset.yaml create mode 100644 kafka/templates/controller-eligible/svc-external-access.yaml create mode 100644 kafka/templates/controller-eligible/svc-headless.yaml create mode 100644 kafka/templates/controller-eligible/vpa.yaml create mode 100644 kafka/templates/extra-list.yaml create mode 100644 kafka/templates/log4j-configmap.yaml create mode 100644 kafka/templates/metrics/jmx-configmap.yaml create mode 100644 kafka/templates/metrics/jmx-servicemonitor.yaml create mode 100644 kafka/templates/metrics/jmx-svc.yaml create mode 100644 kafka/templates/metrics/prometheusrule.yaml create mode 100644 kafka/templates/networkpolicy.yaml create mode 100644 kafka/templates/provisioning/job.yaml create mode 100644 kafka/templates/provisioning/serviceaccount.yaml create mode 100644 kafka/templates/provisioning/tls-secret.yaml create mode 100644 kafka/templates/rbac/role.yaml create mode 100644 kafka/templates/rbac/rolebinding.yaml create mode 100644 kafka/templates/rbac/serviceaccount.yaml create mode 100644 kafka/templates/scripts-configmap.yaml create mode 100644 kafka/templates/secrets.yaml create mode 100644 kafka/templates/svc.yaml create mode 100644 kafka/templates/tls-secret.yaml create mode 100644 kafka/templates/vault-setup.yaml create mode 100644 kafka/values.yaml create mode 100644 livekit/livekit-egress/.helmignore create mode 100644 livekit/livekit-egress/Chart.yaml create mode 100644 livekit/livekit-egress/templates/NOTES.txt create mode 100644 livekit/livekit-egress/templates/_helpers.tpl create mode 100644 livekit/livekit-egress/templates/configmap.yaml create mode 100644 livekit/livekit-egress/templates/deployment.yaml create mode 100644 livekit/livekit-egress/templates/hpa.yaml create mode 100644 livekit/livekit-egress/templates/serviceaccount.yaml create mode 100644 livekit/livekit-egress/values.yaml create mode 100644 livekit/livekit-server/.helmignore create mode 100644 livekit/livekit-server/Chart.yaml create mode 100644 livekit/livekit-server/templates/NOTES.txt create mode 100644 livekit/livekit-server/templates/_helpers.tpl create mode 100644 livekit/livekit-server/templates/backendconfig.yaml create mode 100644 livekit/livekit-server/templates/configmap.yaml create mode 100644 livekit/livekit-server/templates/deployment.yaml create mode 100644 livekit/livekit-server/templates/hpa.yaml create mode 100644 livekit/livekit-server/templates/ingress.yaml create mode 100644 livekit/livekit-server/templates/ingress_turn.yaml create mode 100644 livekit/livekit-server/templates/secret.yaml create mode 100644 livekit/livekit-server/templates/service.yaml create mode 100644 livekit/livekit-server/templates/serviceaccount.yaml create mode 100644 livekit/livekit-server/templates/servicemonitor.yaml create mode 100644 livekit/livekit-server/templates/tests/test-connection.yaml create mode 100644 livekit/livekit-server/templates/turnloadbalancer.yaml create mode 100644 livekit/livekit-server/values.yaml create mode 100644 nfs-subdir-external-provisioner/Chart.yaml create mode 100644 nfs-subdir-external-provisioner/README.md create mode 100644 nfs-subdir-external-provisioner/ci/test-values.yaml create mode 100644 nfs-subdir-external-provisioner/templates/_helpers.tpl create mode 100644 nfs-subdir-external-provisioner/templates/clusterrole.yaml create mode 100644 nfs-subdir-external-provisioner/templates/clusterrolebinding.yaml create mode 100644 nfs-subdir-external-provisioner/templates/deployment.yaml create mode 100644 nfs-subdir-external-provisioner/templates/persistentvolume.yaml create mode 100644 nfs-subdir-external-provisioner/templates/persistentvolumeclaim.yaml create mode 100644 nfs-subdir-external-provisioner/templates/poddisruptionbudget.yaml create mode 100644 nfs-subdir-external-provisioner/templates/podsecuritypolicy.yaml create mode 100644 nfs-subdir-external-provisioner/templates/role.yaml create mode 100644 nfs-subdir-external-provisioner/templates/rolebinding.yaml create mode 100644 nfs-subdir-external-provisioner/templates/serviceaccount.yaml create mode 100644 nfs-subdir-external-provisioner/templates/storageclass.yaml create mode 100644 nfs-subdir-external-provisioner/values.yaml create mode 100644 postgresql-ha/.helmignore create mode 100644 postgresql-ha/Chart.lock create mode 100644 postgresql-ha/Chart.yaml create mode 100644 postgresql-ha/README.md create mode 100644 postgresql-ha/charts/common/.helmignore create mode 100644 postgresql-ha/charts/common/Chart.yaml create mode 100644 postgresql-ha/charts/common/README.md create mode 100644 postgresql-ha/charts/common/templates/_affinities.tpl create mode 100644 postgresql-ha/charts/common/templates/_capabilities.tpl create mode 100644 postgresql-ha/charts/common/templates/_compatibility.tpl create mode 100644 postgresql-ha/charts/common/templates/_errors.tpl create mode 100644 postgresql-ha/charts/common/templates/_images.tpl create mode 100644 postgresql-ha/charts/common/templates/_ingress.tpl create mode 100644 postgresql-ha/charts/common/templates/_labels.tpl create mode 100644 postgresql-ha/charts/common/templates/_names.tpl create mode 100644 postgresql-ha/charts/common/templates/_resources.tpl create mode 100644 postgresql-ha/charts/common/templates/_secrets.tpl create mode 100644 postgresql-ha/charts/common/templates/_storage.tpl create mode 100644 postgresql-ha/charts/common/templates/_tplvalues.tpl create mode 100644 postgresql-ha/charts/common/templates/_utils.tpl create mode 100644 postgresql-ha/charts/common/templates/_warnings.tpl create mode 100644 postgresql-ha/charts/common/templates/validations/_cassandra.tpl create mode 100644 postgresql-ha/charts/common/templates/validations/_mariadb.tpl create mode 100644 postgresql-ha/charts/common/templates/validations/_mongodb.tpl create mode 100644 postgresql-ha/charts/common/templates/validations/_mysql.tpl create mode 100644 postgresql-ha/charts/common/templates/validations/_postgresql.tpl create mode 100644 postgresql-ha/charts/common/templates/validations/_redis.tpl create mode 100644 postgresql-ha/charts/common/templates/validations/_validations.tpl create mode 100644 postgresql-ha/charts/common/values.yaml create mode 100644 postgresql-ha/templates/NOTES.txt create mode 100644 postgresql-ha/templates/_helpers.tpl create mode 100644 postgresql-ha/templates/backup/cronjob.yaml create mode 100644 postgresql-ha/templates/backup/pvc.yaml create mode 100644 postgresql-ha/templates/extra-list.yaml create mode 100644 postgresql-ha/templates/ldap-secrets.yaml create mode 100644 postgresql-ha/templates/metrics-configmap.yaml create mode 100644 postgresql-ha/templates/pgpool/configmap.yaml create mode 100644 postgresql-ha/templates/pgpool/custom-users-secrets.yaml create mode 100644 postgresql-ha/templates/pgpool/deployment.yaml create mode 100644 postgresql-ha/templates/pgpool/initdb-scripts-configmap.yaml create mode 100644 postgresql-ha/templates/pgpool/networkpolicy.yaml create mode 100644 postgresql-ha/templates/pgpool/pdb.yaml create mode 100644 postgresql-ha/templates/pgpool/secrets.yaml create mode 100644 postgresql-ha/templates/pgpool/service.yaml create mode 100644 postgresql-ha/templates/podsecuritypolicy.yaml create mode 100644 postgresql-ha/templates/postgresql/configmap.yaml create mode 100644 postgresql-ha/templates/postgresql/extended-configmap.yaml create mode 100644 postgresql-ha/templates/postgresql/hooks-scripts-configmap.yaml create mode 100644 postgresql-ha/templates/postgresql/initdb-scripts-configmap.yaml create mode 100644 postgresql-ha/templates/postgresql/metrics-service.yaml create mode 100644 postgresql-ha/templates/postgresql/networkpolicy.yaml create mode 100644 postgresql-ha/templates/postgresql/pdb.yaml create mode 100644 postgresql-ha/templates/postgresql/secrets.yaml create mode 100644 postgresql-ha/templates/postgresql/service-headless.yaml create mode 100644 postgresql-ha/templates/postgresql/service-witness.yaml create mode 100644 postgresql-ha/templates/postgresql/service.yaml create mode 100644 postgresql-ha/templates/postgresql/servicemonitor.yaml create mode 100644 postgresql-ha/templates/postgresql/statefulset.yaml create mode 100644 postgresql-ha/templates/postgresql/witness-pdb.yaml create mode 100644 postgresql-ha/templates/postgresql/witness-statefulset.yaml create mode 100644 postgresql-ha/templates/role.yaml create mode 100644 postgresql-ha/templates/rolebinding.yaml create mode 100644 postgresql-ha/templates/serviceaccount.yaml create mode 100644 postgresql-ha/templates/tls-secrets.yaml create mode 100644 postgresql-ha/templates/vault-setup.yaml create mode 100644 postgresql-ha/values.yaml create mode 100644 postgresql/.helmignore create mode 100644 postgresql/Chart.lock create mode 100644 postgresql/Chart.yaml create mode 100644 postgresql/README.md create mode 100644 postgresql/charts/common/.helmignore create mode 100644 postgresql/charts/common/Chart.yaml create mode 100644 postgresql/charts/common/README.md create mode 100644 postgresql/charts/common/templates/_affinities.tpl create mode 100644 postgresql/charts/common/templates/_capabilities.tpl create mode 100644 postgresql/charts/common/templates/_compatibility.tpl create mode 100644 postgresql/charts/common/templates/_errors.tpl create mode 100644 postgresql/charts/common/templates/_images.tpl create mode 100644 postgresql/charts/common/templates/_ingress.tpl create mode 100644 postgresql/charts/common/templates/_labels.tpl create mode 100644 postgresql/charts/common/templates/_names.tpl create mode 100644 postgresql/charts/common/templates/_resources.tpl create mode 100644 postgresql/charts/common/templates/_secrets.tpl create mode 100644 postgresql/charts/common/templates/_storage.tpl create mode 100644 postgresql/charts/common/templates/_tplvalues.tpl create mode 100644 postgresql/charts/common/templates/_utils.tpl create mode 100644 postgresql/charts/common/templates/_warnings.tpl create mode 100644 postgresql/charts/common/templates/validations/_cassandra.tpl create mode 100644 postgresql/charts/common/templates/validations/_mariadb.tpl create mode 100644 postgresql/charts/common/templates/validations/_mongodb.tpl create mode 100644 postgresql/charts/common/templates/validations/_mysql.tpl create mode 100644 postgresql/charts/common/templates/validations/_postgresql.tpl create mode 100644 postgresql/charts/common/templates/validations/_redis.tpl create mode 100644 postgresql/charts/common/templates/validations/_validations.tpl create mode 100644 postgresql/charts/common/values.yaml create mode 100644 postgresql/templates/NOTES.txt create mode 100644 postgresql/templates/_helpers.tpl create mode 100644 postgresql/templates/backup/cronjob.yaml create mode 100644 postgresql/templates/backup/networkpolicy.yaml create mode 100644 postgresql/templates/backup/pvc.yaml create mode 100644 postgresql/templates/extra-list.yaml create mode 100644 postgresql/templates/primary/configmap.yaml create mode 100644 postgresql/templates/primary/extended-configmap.yaml create mode 100644 postgresql/templates/primary/initialization-configmap.yaml create mode 100644 postgresql/templates/primary/metrics-configmap.yaml create mode 100644 postgresql/templates/primary/metrics-svc.yaml create mode 100644 postgresql/templates/primary/networkpolicy.yaml create mode 100644 postgresql/templates/primary/pdb.yaml create mode 100644 postgresql/templates/primary/preinitialization-configmap.yaml create mode 100644 postgresql/templates/primary/servicemonitor.yaml create mode 100644 postgresql/templates/primary/statefulset.yaml create mode 100644 postgresql/templates/primary/svc-headless.yaml create mode 100644 postgresql/templates/primary/svc.yaml create mode 100644 postgresql/templates/prometheusrule.yaml create mode 100644 postgresql/templates/psp.yaml create mode 100644 postgresql/templates/read/extended-configmap.yaml create mode 100644 postgresql/templates/read/metrics-configmap.yaml create mode 100644 postgresql/templates/read/metrics-svc.yaml create mode 100644 postgresql/templates/read/networkpolicy.yaml create mode 100644 postgresql/templates/read/pdb.yaml create mode 100644 postgresql/templates/read/servicemonitor.yaml create mode 100644 postgresql/templates/read/statefulset.yaml create mode 100644 postgresql/templates/read/svc-headless.yaml create mode 100644 postgresql/templates/read/svc.yaml create mode 100644 postgresql/templates/role.yaml create mode 100644 postgresql/templates/rolebinding.yaml create mode 100644 postgresql/templates/secrets.yaml create mode 100644 postgresql/templates/serviceaccount.yaml create mode 100644 postgresql/templates/tls-secrets.yaml create mode 100644 postgresql/templates/update-password/job.yaml create mode 100644 postgresql/templates/update-password/new-secret.yaml create mode 100644 postgresql/templates/update-password/previous-secret.yaml create mode 100644 postgresql/values.schema.json create mode 100644 postgresql/values.yaml create mode 100644 redis/.helmignore create mode 100644 redis/CHANGELOG.md create mode 100644 redis/Chart.lock create mode 100644 redis/Chart.yaml create mode 100644 redis/README.md create mode 100644 redis/img/redis-cluster-topology.png create mode 100644 redis/img/redis-topology.png create mode 100644 redis/templates/NOTES.txt create mode 100644 redis/templates/_helpers.tpl create mode 100644 redis/templates/configmap.yaml create mode 100644 redis/templates/extra-list.yaml create mode 100644 redis/templates/headless-svc.yaml create mode 100644 redis/templates/health-configmap.yaml create mode 100644 redis/templates/master/application.yaml create mode 100644 redis/templates/master/pdb.yaml create mode 100644 redis/templates/master/psp.yaml create mode 100644 redis/templates/master/pvc.yaml create mode 100644 redis/templates/master/service.yaml create mode 100644 redis/templates/master/serviceaccount.yaml create mode 100644 redis/templates/metrics-svc.yaml create mode 100644 redis/templates/networkpolicy.yaml create mode 100644 redis/templates/podmonitor.yaml create mode 100644 redis/templates/prometheusrule.yaml create mode 100644 redis/templates/replicas/application.yaml create mode 100644 redis/templates/replicas/hpa.yaml create mode 100644 redis/templates/replicas/pdb.yaml create mode 100644 redis/templates/replicas/service.yaml create mode 100644 redis/templates/replicas/serviceaccount.yaml create mode 100644 redis/templates/role.yaml create mode 100644 redis/templates/rolebinding.yaml create mode 100644 redis/templates/scripts-configmap.yaml create mode 100644 redis/templates/secret-svcbind.yaml create mode 100644 redis/templates/secret.yaml create mode 100644 redis/templates/sentinel/hpa.yaml create mode 100644 redis/templates/sentinel/node-services.yaml create mode 100644 redis/templates/sentinel/pdb.yaml create mode 100644 redis/templates/sentinel/ports-configmap.yaml create mode 100644 redis/templates/sentinel/service.yaml create mode 100644 redis/templates/sentinel/statefulset.yaml create mode 100644 redis/templates/serviceaccount.yaml create mode 100644 redis/templates/servicemonitor.yaml create mode 100644 redis/templates/svc-external.yaml create mode 100644 redis/templates/tls-secret.yaml create mode 100644 redis/values.schema.json create mode 100644 redis/values.yaml create mode 100644 vault-secrets-operator/.helmignore create mode 100644 vault-secrets-operator/Chart.yaml create mode 100644 vault-secrets-operator/crds/secrets.hashicorp.com_hcpauths.yaml create mode 100644 vault-secrets-operator/crds/secrets.hashicorp.com_hcpvaultsecretsapps.yaml create mode 100644 vault-secrets-operator/crds/secrets.hashicorp.com_secrettransformations.yaml create mode 100644 vault-secrets-operator/crds/secrets.hashicorp.com_vaultauthglobals.yaml create mode 100644 vault-secrets-operator/crds/secrets.hashicorp.com_vaultauths.yaml create mode 100644 vault-secrets-operator/crds/secrets.hashicorp.com_vaultconnections.yaml create mode 100644 vault-secrets-operator/crds/secrets.hashicorp.com_vaultdynamicsecrets.yaml create mode 100644 vault-secrets-operator/crds/secrets.hashicorp.com_vaultpkisecrets.yaml create mode 100644 vault-secrets-operator/crds/secrets.hashicorp.com_vaultstaticsecrets.yaml create mode 100644 vault-secrets-operator/templates/_helpers.tpl create mode 100644 vault-secrets-operator/templates/cluster-role-binding.yaml create mode 100644 vault-secrets-operator/templates/clusterrole-aggregated-editor.yaml create mode 100644 vault-secrets-operator/templates/clusterrole-aggregated-viewer.yaml create mode 100644 vault-secrets-operator/templates/default-transit-auth-method.yaml create mode 100644 vault-secrets-operator/templates/default-vault-auth-method.yaml create mode 100644 vault-secrets-operator/templates/default-vault-connection.yaml create mode 100644 vault-secrets-operator/templates/deployment.yaml create mode 100644 vault-secrets-operator/templates/hcpauth_editor_role.yaml create mode 100644 vault-secrets-operator/templates/hcpauth_viewer_role.yaml create mode 100644 vault-secrets-operator/templates/hcpvaultsecretsapp_editor_role.yaml create mode 100644 vault-secrets-operator/templates/hcpvaultsecretsapp_viewer_role.yaml create mode 100644 vault-secrets-operator/templates/hook-upgrade-crds.yaml create mode 100644 vault-secrets-operator/templates/leader-election-rbac.yaml create mode 100644 vault-secrets-operator/templates/manager-config.yaml create mode 100644 vault-secrets-operator/templates/metrics-reader-rbac.yaml create mode 100644 vault-secrets-operator/templates/metrics-service.yaml create mode 100644 vault-secrets-operator/templates/prometheus-servicemonitor.yaml create mode 100644 vault-secrets-operator/templates/proxy-rbac.yaml create mode 100644 vault-secrets-operator/templates/role.yaml create mode 100644 vault-secrets-operator/templates/secrettransformation_editor_role.yaml create mode 100644 vault-secrets-operator/templates/secrettransformation_viewer_role.yaml create mode 100644 vault-secrets-operator/templates/tests/test-runner.yaml create mode 100644 vault-secrets-operator/templates/vaultauth_editor_role.yaml create mode 100644 vault-secrets-operator/templates/vaultauth_viewer_role.yaml create mode 100644 vault-secrets-operator/templates/vaultauthglobal_editor_role.yaml create mode 100644 vault-secrets-operator/templates/vaultauthglobal_viewer_role.yaml create mode 100644 vault-secrets-operator/templates/vaultconnection_editor_role.yaml create mode 100644 vault-secrets-operator/templates/vaultconnection_viewer_role.yaml create mode 100644 vault-secrets-operator/templates/vaultdynamicsecret_editor_role.yaml create mode 100644 vault-secrets-operator/templates/vaultdynamicsecret_viewer_role.yaml create mode 100644 vault-secrets-operator/templates/vaultpkisecret_editor_role.yaml create mode 100644 vault-secrets-operator/templates/vaultpkisecret_viewer_role.yaml create mode 100644 vault-secrets-operator/templates/vaultstaticsecret_editor_role.yaml create mode 100644 vault-secrets-operator/templates/vaultstaticsecret_viewer_role.yaml create mode 100644 vault-secrets-operator/values.yaml create mode 100644 vault/.helmignore create mode 100644 vault/Chart.yaml create mode 100644 vault/Makefile create mode 100644 vault/README.md create mode 100644 vault/templates/NOTES.txt create mode 100644 vault/templates/_helpers.tpl create mode 100644 vault/templates/csi-agent-configmap.yaml create mode 100644 vault/templates/csi-clusterrole.yaml create mode 100644 vault/templates/csi-clusterrolebinding.yaml create mode 100644 vault/templates/csi-daemonset.yaml create mode 100644 vault/templates/csi-role.yaml create mode 100644 vault/templates/csi-rolebinding.yaml create mode 100644 vault/templates/csi-serviceaccount.yaml create mode 100644 vault/templates/injector-certs-secret.yaml create mode 100644 vault/templates/injector-clusterrole.yaml create mode 100644 vault/templates/injector-clusterrolebinding.yaml create mode 100644 vault/templates/injector-deployment.yaml create mode 100644 vault/templates/injector-disruptionbudget.yaml create mode 100644 vault/templates/injector-mutating-webhook.yaml create mode 100644 vault/templates/injector-network-policy.yaml create mode 100644 vault/templates/injector-psp-role.yaml create mode 100644 vault/templates/injector-psp-rolebinding.yaml create mode 100644 vault/templates/injector-psp.yaml create mode 100644 vault/templates/injector-role.yaml create mode 100644 vault/templates/injector-rolebinding.yaml create mode 100644 vault/templates/injector-service.yaml create mode 100644 vault/templates/injector-serviceaccount.yaml create mode 100644 vault/templates/prometheus-prometheusrules.yaml create mode 100644 vault/templates/prometheus-servicemonitor.yaml create mode 100644 vault/templates/server-clusterrolebinding.yaml create mode 100644 vault/templates/server-config-configmap.yaml create mode 100644 vault/templates/server-discovery-role.yaml create mode 100644 vault/templates/server-discovery-rolebinding.yaml create mode 100644 vault/templates/server-disruptionbudget.yaml create mode 100644 vault/templates/server-ha-active-service.yaml create mode 100644 vault/templates/server-ha-standby-service.yaml create mode 100644 vault/templates/server-headless-service.yaml create mode 100644 vault/templates/server-ingress.yaml create mode 100644 vault/templates/server-network-policy.yaml create mode 100644 vault/templates/server-psp-role.yaml create mode 100644 vault/templates/server-psp-rolebinding.yaml create mode 100644 vault/templates/server-psp.yaml create mode 100644 vault/templates/server-route.yaml create mode 100644 vault/templates/server-service.yaml create mode 100644 vault/templates/server-serviceaccount-secret.yaml create mode 100644 vault/templates/server-serviceaccount.yaml create mode 100644 vault/templates/server-statefulset.yaml create mode 100644 vault/templates/tests/server-test.yaml create mode 100644 vault/templates/ui-service.yaml create mode 100644 vault/test/README.md create mode 100644 vault/test/acceptance/_helpers.bash create mode 100644 vault/test/acceptance/csi-test/nginx.yaml create mode 100644 vault/test/acceptance/csi-test/vault-kv-secretproviderclass.yaml create mode 100644 vault/test/acceptance/csi-test/vault-policy.hcl create mode 100644 vault/test/acceptance/csi.bats create mode 100644 vault/test/acceptance/helm-test.bats create mode 100644 vault/test/acceptance/injector-cross-namespace.bats create mode 100644 vault/test/acceptance/injector-leader-elector.bats create mode 100644 vault/test/acceptance/injector-test/bootstrap-cross-namespace.sh create mode 100755 vault/test/acceptance/injector-test/bootstrap.sh create mode 100644 vault/test/acceptance/injector-test/job.yaml create mode 100644 vault/test/acceptance/injector-test/pg-deployment.yaml create mode 100644 vault/test/acceptance/injector-test/pgdump-policy.hcl create mode 100644 vault/test/acceptance/injector.bats create mode 100644 vault/test/acceptance/server-annotations.bats create mode 100644 vault/test/acceptance/server-dev.bats create mode 100644 vault/test/acceptance/server-ha-enterprise-dr.bats create mode 100644 vault/test/acceptance/server-ha-enterprise-perf.bats create mode 100644 vault/test/acceptance/server-ha-raft.bats create mode 100644 vault/test/acceptance/server-ha.bats create mode 100644 vault/test/acceptance/server-telemetry.bats create mode 100644 vault/test/acceptance/server-test/annotations-overrides.yaml create mode 100644 vault/test/acceptance/server-test/vault-server.yaml create mode 100644 vault/test/acceptance/server-test/vault-telemetry.yaml create mode 100644 vault/test/acceptance/server.bats create mode 100644 vault/test/chart/_helpers.bash create mode 100644 vault/test/chart/verifier.bats create mode 100644 vault/test/docker/Test.dockerfile create mode 100644 vault/test/kind/config.yaml create mode 100644 vault/test/terraform/main.tf create mode 100644 vault/test/terraform/outputs.tf create mode 100644 vault/test/terraform/variables.tf create mode 100644 vault/test/unit/_helpers.bash create mode 100644 vault/test/unit/csi-agent-configmap.bats create mode 100644 vault/test/unit/csi-clusterrole.bats create mode 100644 vault/test/unit/csi-clusterrolebinding.bats create mode 100644 vault/test/unit/csi-daemonset.bats create mode 100644 vault/test/unit/csi-role.bats create mode 100644 vault/test/unit/csi-rolebinding.bats create mode 100644 vault/test/unit/csi-serviceaccount.bats create mode 100755 vault/test/unit/injector-clusterrole.bats create mode 100755 vault/test/unit/injector-clusterrolebinding.bats create mode 100755 vault/test/unit/injector-deployment.bats create mode 100755 vault/test/unit/injector-disruptionbudget.bats create mode 100644 vault/test/unit/injector-leader-elector.bats create mode 100755 vault/test/unit/injector-mutating-webhook.bats create mode 100644 vault/test/unit/injector-psp-role.bats create mode 100644 vault/test/unit/injector-psp-rolebinding.bats create mode 100644 vault/test/unit/injector-psp.bats create mode 100755 vault/test/unit/injector-service.bats create mode 100755 vault/test/unit/injector-serviceaccount.bats create mode 100755 vault/test/unit/prometheus-prometheusrules.bats create mode 100755 vault/test/unit/prometheus-servicemonitor.bats create mode 100644 vault/test/unit/schema.bats create mode 100755 vault/test/unit/server-clusterrolebinding.bats create mode 100755 vault/test/unit/server-configmap.bats create mode 100755 vault/test/unit/server-dev-statefulset.bats create mode 100755 vault/test/unit/server-discovery-role.bats create mode 100755 vault/test/unit/server-discovery-rolebinding.bats create mode 100755 vault/test/unit/server-ha-active-service.bats create mode 100755 vault/test/unit/server-ha-disruptionbudget.bats create mode 100755 vault/test/unit/server-ha-standby-service.bats create mode 100755 vault/test/unit/server-ha-statefulset.bats create mode 100644 vault/test/unit/server-headless-service.bats create mode 100755 vault/test/unit/server-ingress.bats create mode 100755 vault/test/unit/server-network-policy.bats create mode 100644 vault/test/unit/server-psp-role.bats create mode 100644 vault/test/unit/server-psp-rolebinding.bats create mode 100644 vault/test/unit/server-psp.bats create mode 100755 vault/test/unit/server-route.bats create mode 100755 vault/test/unit/server-service.bats create mode 100644 vault/test/unit/server-serviceaccount-secret.bats create mode 100755 vault/test/unit/server-serviceaccount.bats create mode 100755 vault/test/unit/server-statefulset.bats create mode 100644 vault/test/unit/server-test.bats create mode 100755 vault/test/unit/ui-service.bats create mode 100644 vault/values.openshift.yaml create mode 100644 vault/values.schema.json create mode 100644 vault/values.yaml diff --git a/README.md b/README.md new file mode 100644 index 0000000..b86bfe8 --- /dev/null +++ b/README.md @@ -0,0 +1,93 @@ +# cw-infra-apps + + + +## Getting started + +To make it easy for you to get started with GitLab, here's a list of recommended next steps. + +Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! + +## Add your files + +- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files +- [ ] [Add files using the command line](https://docs.gitlab.com/topics/git/add_files/#add-files-to-a-git-repository) or push an existing Git repository with the following command: + +``` +cd existing_repo +git remote add origin https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git +git branch -M main +git push -uf origin main +``` + +## Integrate with your tools + +- [ ] [Set up project integrations](https://gitlab.ii-p001.local/cw-devops/cw-infra-apps/-/settings/integrations) + +## Collaborate with your team + +- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/) +- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) +- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically) +- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/) +- [ ] [Set auto-merge](https://docs.gitlab.com/user/project/merge_requests/auto_merge/) + +## Test and Deploy + +Use the built-in continuous integration in GitLab. + +- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/) +- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) +- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) +- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) +- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) + +*** + +# Editing this README + +When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template. + +## Suggestions for a good README + +Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. + +## Name +Choose a self-explaining name for your project. + +## Description +Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. + +## Badges +On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. + +## Visuals +Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. + +## Installation +Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. + +## Usage +Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. + +## Support +Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. + +## Roadmap +If you have ideas for releases in the future, it is a good idea to list them in the README. + +## Contributing +State if you are open to contributions and what your requirements are for accepting them. + +For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. + +You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. + +## Authors and acknowledgment +Show your appreciation to those who have contributed to the project. + +## License +For open source projects, say how it is licensed. + +## Project status +If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. diff --git a/argo-infra-apps/cassandra.yaml b/argo-infra-apps/cassandra.yaml new file mode 100644 index 0000000..50881df --- /dev/null +++ b/argo-infra-apps/cassandra.yaml @@ -0,0 +1,265 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"argoproj.io/v1alpha1","kind":"Application","metadata":{"annotations":{},"creationTimestamp":"2025-03-18T14:41:54Z","generation":492,"labels":{"app.kubernetes.io/instance":"argo-infra-apps"},"name":"cassandra","namespace":"argocd","resourceVersion":"424046","uid":"b92c294e-f499-4495-8564-f785527a338b"},"spec":{"destination":{"namespace":"cassandra","server":"https://kubernetes.default.svc"},"project":"default","source":{"path":"cassandra","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"},"syncPolicy":{"automated":{"prune":true,"selfHeal":true},"syncOptions":["CreateNamespace=true"]}},"status":{"controllerNamespace":"argocd","health":{"status":"Healthy"},"history":[{"deployStartedAt":"2025-03-18T14:41:57Z","deployedAt":"2025-03-18T14:42:00Z","id":0,"initiatedBy":{"automated":true},"revision":"2dbc2c07368f5ace43bbb70938daa99e8b498589","source":{"path":"cassandra","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}},{"deployStartedAt":"2025-03-18T17:10:36Z","deployedAt":"2025-03-18T17:10:37Z","id":1,"initiatedBy":{"automated":true},"revision":"f0b5d9ebe0e06180a2425f74ba70882be0cb41ce","source":{"path":"cassandra","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}},{"deployStartedAt":"2025-03-19T10:37:36Z","deployedAt":"2025-03-19T10:37:37Z","id":2,"initiatedBy":{"automated":true},"revision":"66c29291453cc31166552c8cfb733467c73d0b33","source":{"path":"cassandra","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}},{"deployStartedAt":"2025-03-19T10:58:36Z","deployedAt":"2025-03-19T10:58:37Z","id":3,"initiatedBy":{"automated":true},"revision":"ea003db2768a9cadc1e8a6ca0c9f6368a165243a","source":{"path":"cassandra","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}}],"operationState":{"finishedAt":"2025-03-19T10:58:37Z","message":"successfully synced (all tasks run)","operation":{"initiatedBy":{"automated":true},"retry":{"limit":5},"sync":{"prune":true,"revision":"ea003db2768a9cadc1e8a6ca0c9f6368a165243a","syncOptions":["CreateNamespace=true"]}},"phase":"Succeeded","startedAt":"2025-03-19T10:58:36Z","syncResult":{"resources":[{"group":"networking.k8s.io","hookPhase":"Running","kind":"NetworkPolicy","message":"networkpolicy.networking.k8s.io/cassandra configured","name":"cassandra","namespace":"cassandra","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"policy","hookPhase":"Running","kind":"PodDisruptionBudget","message":"poddisruptionbudget.policy/cassandra configured","name":"cassandra","namespace":"cassandra","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"ServiceAccount","message":"serviceaccount/cassandra unchanged","name":"cassandra","namespace":"cassandra","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"Secret","message":"secret/cassandra configured","name":"cassandra","namespace":"cassandra","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"ConfigMap","message":"configmap/cassandra-metrics-conf unchanged","name":"cassandra-metrics-conf","namespace":"cassandra","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"Service","message":"service/cassandra-headless unchanged","name":"cassandra-headless","namespace":"cassandra","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"Service","message":"service/cassandra configured","name":"cassandra","namespace":"cassandra","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"apps","hookPhase":"Running","kind":"StatefulSet","message":"statefulset.apps/cassandra configured","name":"cassandra","namespace":"cassandra","status":"Synced","syncPhase":"Sync","version":"v1"}],"revision":"ea003db2768a9cadc1e8a6ca0c9f6368a165243a","source":{"path":"cassandra","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}}},"reconciledAt":"2025-03-19T13:52:34Z","resources":[{"kind":"ConfigMap","name":"cassandra-metrics-conf","namespace":"cassandra","status":"Synced","version":"v1"},{"kind":"Secret","name":"cassandra","namespace":"cassandra","status":"Synced","version":"v1"},{"health":{"status":"Healthy"},"kind":"Service","name":"cassandra","namespace":"cassandra","status":"Synced","version":"v1"},{"health":{"status":"Healthy"},"kind":"Service","name":"cassandra-headless","namespace":"cassandra","status":"Synced","version":"v1"},{"kind":"ServiceAccount","name":"cassandra","namespace":"cassandra","status":"Synced","version":"v1"},{"group":"apps","health":{"message":"statefulset rolling update complete 1 pods at revision cassandra-6878c77ff9...","status":"Healthy"},"kind":"StatefulSet","name":"cassandra","namespace":"cassandra","status":"Synced","version":"v1"},{"group":"networking.k8s.io","kind":"NetworkPolicy","name":"cassandra","namespace":"cassandra","status":"Synced","version":"v1"},{"group":"policy","kind":"PodDisruptionBudget","name":"cassandra","namespace":"cassandra","status":"Synced","version":"v1"}],"sourceType":"Helm","summary":{"images":["docker.io/bitnami/cassandra:5.0.3-debian-12-r6"]},"sync":{"comparedTo":{"destination":{"namespace":"cassandra","server":"https://kubernetes.default.svc"},"source":{"path":"cassandra","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}},"revision":"ea003db2768a9cadc1e8a6ca0c9f6368a165243a","status":"Synced"}}} + creationTimestamp: "2025-03-19T14:00:58Z" + generation: 55 + labels: + app.kubernetes.io/instance: argo-infra-apps + name: cassandra + namespace: argocd + resourceVersion: "442200" + uid: dcda9843-8c6e-4465-9f41-43be4d47e794 +spec: + destination: + namespace: cassandra + server: https://kubernetes.default.svc + project: default + source: + path: cassandra + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true +status: + controllerNamespace: argocd + health: + status: Healthy + history: + - deployStartedAt: "2025-03-18T14:41:57Z" + deployedAt: "2025-03-18T14:42:00Z" + id: 0 + initiatedBy: + automated: true + revision: 2dbc2c07368f5ace43bbb70938daa99e8b498589 + source: + path: cassandra + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-03-18T17:10:36Z" + deployedAt: "2025-03-18T17:10:37Z" + id: 1 + initiatedBy: + automated: true + revision: f0b5d9ebe0e06180a2425f74ba70882be0cb41ce + source: + path: cassandra + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-03-19T10:37:36Z" + deployedAt: "2025-03-19T10:37:37Z" + id: 2 + initiatedBy: + automated: true + revision: 66c29291453cc31166552c8cfb733467c73d0b33 + source: + path: cassandra + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-03-19T10:58:36Z" + deployedAt: "2025-03-19T10:58:37Z" + id: 3 + initiatedBy: + automated: true + revision: ea003db2768a9cadc1e8a6ca0c9f6368a165243a + source: + path: cassandra + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-03-19T14:01:01Z" + deployedAt: "2025-03-19T14:01:02Z" + id: 4 + initiatedBy: + automated: true + revision: ccbcd028530e5528739ce1fd9d30fa1a835db178 + source: + path: cassandra + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-03-19T14:04:38Z" + deployedAt: "2025-03-19T14:04:39Z" + id: 5 + initiatedBy: + automated: true + revision: 170f1d93a41905281cbf22e6e4bd394d1fd57b7f + source: + path: cassandra + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-03-19T14:34:38Z" + deployedAt: "2025-03-19T14:34:39Z" + id: 6 + initiatedBy: + automated: true + revision: 51a8196fc681a3e098bb86eb1f2dd0889bfab910 + source: + path: cassandra + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + operationState: + finishedAt: "2025-03-19T14:34:39Z" + message: successfully synced (all tasks run) + operation: + initiatedBy: + automated: true + retry: + limit: 5 + sync: + prune: true + revision: 51a8196fc681a3e098bb86eb1f2dd0889bfab910 + syncOptions: + - CreateNamespace=true + phase: Succeeded + startedAt: "2025-03-19T14:34:38Z" + syncResult: + resources: + - group: networking.k8s.io + hookPhase: Running + kind: NetworkPolicy + message: networkpolicy.networking.k8s.io/cassandra configured + name: cassandra + namespace: cassandra + status: Synced + syncPhase: Sync + version: v1 + - group: policy + hookPhase: Running + kind: PodDisruptionBudget + message: poddisruptionbudget.policy/cassandra configured + name: cassandra + namespace: cassandra + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: ServiceAccount + message: serviceaccount/cassandra unchanged + name: cassandra + namespace: cassandra + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Secret + message: secret/cassandra configured + name: cassandra + namespace: cassandra + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: ConfigMap + message: configmap/cassandra-metrics-conf unchanged + name: cassandra-metrics-conf + namespace: cassandra + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: service/cassandra-headless unchanged + name: cassandra-headless + namespace: cassandra + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: service/cassandra configured + name: cassandra + namespace: cassandra + status: Synced + syncPhase: Sync + version: v1 + - group: apps + hookPhase: Running + kind: StatefulSet + message: statefulset.apps/cassandra configured + name: cassandra + namespace: cassandra + status: Synced + syncPhase: Sync + version: v1 + revision: 51a8196fc681a3e098bb86eb1f2dd0889bfab910 + source: + path: cassandra + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + reconciledAt: "2025-03-19T15:34:34Z" + resources: + - kind: ConfigMap + name: cassandra-metrics-conf + namespace: cassandra + status: Synced + version: v1 + - kind: Secret + name: cassandra + namespace: cassandra + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: cassandra + namespace: cassandra + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: cassandra-headless + namespace: cassandra + status: Synced + version: v1 + - kind: ServiceAccount + name: cassandra + namespace: cassandra + status: Synced + version: v1 + - group: apps + health: + message: statefulset rolling update complete 1 pods at revision cassandra-6878c77ff9... + status: Healthy + kind: StatefulSet + name: cassandra + namespace: cassandra + status: Synced + version: v1 + - group: networking.k8s.io + kind: NetworkPolicy + name: cassandra + namespace: cassandra + status: Synced + version: v1 + - group: policy + kind: PodDisruptionBudget + name: cassandra + namespace: cassandra + status: Synced + version: v1 + sourceType: Helm + summary: + images: + - docker.io/bitnami/cassandra:5.0.3-debian-12-r6 + sync: + comparedTo: + destination: + namespace: cassandra + server: https://kubernetes.default.svc + source: + path: cassandra + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + revision: 51a8196fc681a3e098bb86eb1f2dd0889bfab910 + status: Synced diff --git a/argo-infra-apps/elasticsearch.yaml b/argo-infra-apps/elasticsearch.yaml new file mode 100644 index 0000000..4490c66 --- /dev/null +++ b/argo-infra-apps/elasticsearch.yaml @@ -0,0 +1,258 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + creationTimestamp: "2025-04-22T07:01:17Z" + generation: 166 + name: elasticsearch + namespace: argocd + resourceVersion: "9726027" + uid: 928fb09c-938a-4ed5-9f05-5f8702d14a5e +spec: + destination: + namespace: elasticsearch + server: https://kubernetes.default.svc + project: default + source: + path: elasticsearch + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + syncPolicy: + automated: {} + syncOptions: + - CreateNamespace=true +status: + controllerNamespace: argocd + health: + status: Healthy + history: + - deployStartedAt: "2025-04-22T09:21:48Z" + deployedAt: "2025-04-22T09:21:48Z" + id: 2 + initiatedBy: + username: admin + revision: 3bb4328927c2b211878533c8928b9aa50d3cb545 + source: + path: elasticsearch + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-04-22T09:22:40Z" + deployedAt: "2025-04-22T09:22:41Z" + id: 3 + initiatedBy: + username: admin + revision: 3bb4328927c2b211878533c8928b9aa50d3cb545 + source: + path: elasticsearch + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-04-22T09:23:22Z" + deployedAt: "2025-04-22T09:23:23Z" + id: 4 + initiatedBy: + username: admin + revision: 3bb4328927c2b211878533c8928b9aa50d3cb545 + source: + path: elasticsearch + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-04-22T09:24:25Z" + deployedAt: "2025-04-22T09:24:28Z" + id: 5 + initiatedBy: + username: admin + revision: 70dfc9595b1a8138455d9225facc018518da5e8a + source: + path: elasticsearch + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-04-22T09:24:28Z" + deployedAt: "2025-04-22T09:24:29Z" + id: 6 + initiatedBy: + automated: true + revision: 3bb4328927c2b211878533c8928b9aa50d3cb545 + source: + path: elasticsearch + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-04-22T09:26:23Z" + deployedAt: "2025-04-22T09:26:24Z" + id: 7 + initiatedBy: + username: admin + revision: 411b0b9894242dca75f4ee170a81ceef4e635b0a + source: + path: elasticsearch + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-04-22T09:26:25Z" + deployedAt: "2025-04-22T09:26:25Z" + id: 8 + initiatedBy: + automated: true + revision: 70dfc9595b1a8138455d9225facc018518da5e8a + source: + path: elasticsearch + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-04-22T09:27:24Z" + deployedAt: "2025-04-22T09:27:25Z" + id: 9 + initiatedBy: + username: admin + revision: 411b0b9894242dca75f4ee170a81ceef4e635b0a + source: + path: elasticsearch + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-04-22T09:27:25Z" + deployedAt: "2025-04-22T09:27:25Z" + id: 10 + initiatedBy: + automated: true + revision: 70dfc9595b1a8138455d9225facc018518da5e8a + source: + path: elasticsearch + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-04-22T09:30:48Z" + deployedAt: "2025-04-22T09:30:48Z" + id: 11 + initiatedBy: + automated: true + revision: 411b0b9894242dca75f4ee170a81ceef4e635b0a + source: + path: elasticsearch + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + operationState: + finishedAt: "2025-04-22T09:30:48Z" + message: successfully synced (all tasks run) + operation: + initiatedBy: + automated: true + retry: + limit: 5 + sync: + revision: 411b0b9894242dca75f4ee170a81ceef4e635b0a + syncOptions: + - CreateNamespace=true + phase: Succeeded + startedAt: "2025-04-22T09:30:48Z" + syncResult: + resources: + - group: policy + hookPhase: Running + kind: PodDisruptionBudget + message: poddisruptionbudget.policy/elasticsearch-master-pdb configured + name: elasticsearch-master-pdb + namespace: elasticsearch + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Secret + message: secret/elasticsearch-master-certs configured + name: elasticsearch-master-certs + namespace: elasticsearch + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Secret + message: secret/elasticsearch-master-credentials configured + name: elasticsearch-master-credentials + namespace: elasticsearch + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: service/elasticsearch-master-headless unchanged + name: elasticsearch-master-headless + namespace: elasticsearch + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: service/elasticsearch-master configured + name: elasticsearch-master + namespace: elasticsearch + status: Synced + syncPhase: Sync + version: v1 + - group: apps + hookPhase: Running + kind: StatefulSet + message: statefulset.apps/elasticsearch-master configured + name: elasticsearch-master + namespace: elasticsearch + status: Synced + syncPhase: Sync + version: v1 + revision: 411b0b9894242dca75f4ee170a81ceef4e635b0a + source: + path: elasticsearch + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + reconciledAt: "2025-04-22T09:36:48Z" + resources: + - kind: Secret + name: elasticsearch-master-certs + namespace: elasticsearch + status: Synced + version: v1 + - kind: Secret + name: elasticsearch-master-credentials + namespace: elasticsearch + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: elasticsearch-master + namespace: elasticsearch + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: elasticsearch-master-headless + namespace: elasticsearch + status: Synced + version: v1 + - group: apps + health: + message: statefulset rolling update complete 3 pods at revision elasticsearch-master-579789bbc... + status: Healthy + kind: StatefulSet + name: elasticsearch-master + namespace: elasticsearch + status: Synced + version: v1 + - group: policy + kind: PodDisruptionBudget + name: elasticsearch-master-pdb + namespace: elasticsearch + status: Synced + version: v1 + sourceType: Helm + summary: + images: + - docker.io/library/elasticsearch:8.5.1 + sync: + comparedTo: + destination: + namespace: elasticsearch + server: https://kubernetes.default.svc + source: + path: elasticsearch + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + revision: 411b0b9894242dca75f4ee170a81ceef4e635b0a + status: Synced diff --git a/argo-infra-apps/grafana.yaml b/argo-infra-apps/grafana.yaml new file mode 100644 index 0000000..8754d7a --- /dev/null +++ b/argo-infra-apps/grafana.yaml @@ -0,0 +1,233 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + creationTimestamp: "2025-04-29T20:35:02Z" + generation: 18 + name: grafana + namespace: argocd + resourceVersion: "12377177" + uid: 5f1ac9c2-48c5-4778-afc3-6a9a2c525a4f +spec: + destination: + namespace: grafana + server: https://kubernetes.default.svc + project: default + source: + path: grafana + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + syncPolicy: + automated: {} + syncOptions: + - CreateNamespace=true +status: + controllerNamespace: argocd + health: + status: Healthy + history: + - deployStartedAt: "2025-04-29T20:35:04Z" + deployedAt: "2025-04-29T20:35:06Z" + id: 0 + initiatedBy: + automated: true + revision: 0144665f14c7e31020dbfa8c9c2746a290caec74 + source: + path: grafana + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + operationState: + finishedAt: "2025-04-29T20:35:07Z" + message: successfully synced (all tasks run) + operation: + initiatedBy: + automated: true + retry: + limit: 5 + sync: + revision: 0144665f14c7e31020dbfa8c9c2746a290caec74 + syncOptions: + - CreateNamespace=true + phase: Succeeded + startedAt: "2025-04-29T20:35:04Z" + syncResult: + resources: + - group: "" + hookPhase: Running + kind: Namespace + message: namespace/grafana created + name: grafana + namespace: "" + status: Synced + syncPhase: PreSync + version: v1 + - group: "" + hookPhase: Running + kind: ServiceAccount + message: serviceaccount/grafana-alloy-metrics created + name: grafana-alloy-metrics + namespace: grafana + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Secret + message: secret/metrics-grafana-k8s-monitoring created + name: metrics-grafana-k8s-monitoring + namespace: grafana + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: ConfigMap + message: configmap/grafana-alloy-metrics created + name: grafana-alloy-metrics + namespace: grafana + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: "clusterrole.rbac.authorization.k8s.io/grafana-alloy-metrics reconciled. + reconciliation required create\n\tmissing rules added:\n\t\t{Verbs:[get + list watch] APIGroups:[ discovery.k8s.io networking.k8s.io] Resources:[endpoints + endpointslices ingresses nodes nodes/proxy nodes/metrics pods services] + ResourceNames:[] NonResourceURLs:[]}\n\t\t{Verbs:[get list watch] APIGroups:[] + Resources:[pods pods/log namespaces] ResourceNames:[] NonResourceURLs:[]}\n\t\t{Verbs:[get + list watch] APIGroups:[monitoring.grafana.com] Resources:[podlogs] ResourceNames:[] + NonResourceURLs:[]}\n\t\t{Verbs:[get list watch] APIGroups:[monitoring.coreos.com] + Resources:[prometheusrules] ResourceNames:[] NonResourceURLs:[]}\n\t\t{Verbs:[get] + APIGroups:[] Resources:[] ResourceNames:[] NonResourceURLs:[/metrics]}\n\t\t{Verbs:[get + list watch] APIGroups:[monitoring.coreos.com] Resources:[podmonitors servicemonitors + probes scrapeconfigs] ResourceNames:[] NonResourceURLs:[]}\n\t\t{Verbs:[get + list watch] APIGroups:[] Resources:[events] ResourceNames:[] NonResourceURLs:[]}\n\t\t{Verbs:[get + list watch] APIGroups:[] Resources:[configmaps secrets] ResourceNames:[] + NonResourceURLs:[]}\n\t\t{Verbs:[get list watch] APIGroups:[apps] Resources:[replicasets] + ResourceNames:[] NonResourceURLs:[]}\n\t\t{Verbs:[get list watch] APIGroups:[extensions] + Resources:[replicasets] ResourceNames:[] NonResourceURLs:[]}. clusterrole.rbac.authorization.k8s.io/grafana-alloy-metrics + configured. Warning: resource clusterroles/grafana-alloy-metrics is missing + the kubectl.kubernetes.io/last-applied-configuration annotation which is + required by apply. apply should only be used on resources created declaratively + by either create --save-config or apply. The missing annotation will be + patched automatically." + name: grafana-alloy-metrics + namespace: grafana + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRoleBinding + message: "clusterrolebinding.rbac.authorization.k8s.io/grafana-alloy-metrics + reconciled. reconciliation required create\n\tmissing subjects added:\n\t\t{Kind:ServiceAccount + APIGroup: Name:grafana-alloy-metrics Namespace:grafana}. clusterrolebinding.rbac.authorization.k8s.io/grafana-alloy-metrics + configured. Warning: resource clusterrolebindings/grafana-alloy-metrics + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically." + name: grafana-alloy-metrics + namespace: grafana + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: service/grafana-alloy-metrics-cluster created + name: grafana-alloy-metrics-cluster + namespace: grafana + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: service/grafana-alloy-metrics created + name: grafana-alloy-metrics + namespace: grafana + status: Synced + syncPhase: Sync + version: v1 + - group: apps + hookPhase: Running + kind: StatefulSet + message: statefulset.apps/grafana-alloy-metrics created + name: grafana-alloy-metrics + namespace: grafana + status: Synced + syncPhase: Sync + version: v1 + revision: 0144665f14c7e31020dbfa8c9c2746a290caec74 + source: + path: grafana + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + reconciledAt: "2025-04-29T20:48:00Z" + resources: + - kind: ConfigMap + name: grafana-alloy-metrics + namespace: grafana + status: Synced + version: v1 + - kind: Secret + name: metrics-grafana-k8s-monitoring + namespace: grafana + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: grafana-alloy-metrics + namespace: grafana + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: grafana-alloy-metrics-cluster + namespace: grafana + status: Synced + version: v1 + - kind: ServiceAccount + name: grafana-alloy-metrics + namespace: grafana + status: Synced + version: v1 + - group: apps + health: + message: 'partitioned roll out complete: 1 new pods have been updated...' + status: Healthy + kind: StatefulSet + name: grafana-alloy-metrics + namespace: grafana + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: grafana-alloy-metrics + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRoleBinding + name: grafana-alloy-metrics + status: Synced + version: v1 + sourceType: Helm + summary: + images: + - docker.io/grafana/alloy:v1.8.2 + - quay.io/prometheus-operator/prometheus-config-reloader:v0.81.0 + sync: + comparedTo: + destination: + namespace: grafana + server: https://kubernetes.default.svc + source: + path: grafana + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + revision: 0144665f14c7e31020dbfa8c9c2746a290caec74 + status: Synced diff --git a/argo-infra-apps/ingress-nginx.yaml b/argo-infra-apps/ingress-nginx.yaml new file mode 100644 index 0000000..6d0d19d --- /dev/null +++ b/argo-infra-apps/ingress-nginx.yaml @@ -0,0 +1,208 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + creationTimestamp: "2025-05-07T15:03:24Z" + generation: 779 + name: ingress-nginx + namespace: argocd + resourceVersion: "15435627" + uid: ecb21cf9-d2a3-409b-87a7-cf1a44b0bbe1 +spec: + destination: + server: https://kubernetes.default.svc + project: default + source: + path: ingress-nginx + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + syncPolicy: + automated: {} +status: + controllerNamespace: argocd + health: + status: Healthy + history: + - deployStartedAt: "2025-05-07T15:03:25Z" + deployedAt: "2025-05-07T15:03:50Z" + id: 0 + initiatedBy: + automated: true + revision: 91f02aa5bf6ced7986e99b89fca21ee4452f7d5c + source: + path: ingress-nginx + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-05-07T15:08:21Z" + deployedAt: "2025-05-07T15:08:35Z" + id: 1 + initiatedBy: + username: admin + revision: 1402201ea91b245cd137ca4e86763bfc5d995ff0 + source: + path: ingress-nginx + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-05-07T15:08:35Z" + deployedAt: "2025-05-07T15:08:49Z" + id: 2 + initiatedBy: + automated: true + revision: 91f02aa5bf6ced7986e99b89fca21ee4452f7d5c + source: + path: ingress-nginx + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-05-08T10:46:45Z" + deployedAt: "2025-05-08T10:46:57Z" + id: 3 + initiatedBy: + automated: true + revision: 36e6d6dc59968e714b0b4ead488c5dc72682094a + source: + path: ingress-nginx + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-05-08T14:28:02Z" + deployedAt: "2025-05-08T14:28:14Z" + id: 4 + initiatedBy: + automated: true + revision: c8b0c0149b5392e63bf832f558305d59d82ae9af + source: + path: ingress-nginx + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-05-08T14:41:29Z" + deployedAt: "2025-05-08T14:41:44Z" + id: 5 + initiatedBy: + automated: true + revision: 6c1a12cdae7ccf40a6ba2282482187045749be6b + source: + path: ingress-nginx + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-05-08T14:53:12Z" + deployedAt: "2025-05-08T14:53:24Z" + id: 6 + initiatedBy: + username: admin + revision: 6c1a12cdae7ccf40a6ba2282482187045749be6b + source: + path: ingress-nginx + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + operationState: + finishedAt: "2025-05-08T14:57:22Z" + message: one or more objects failed to apply (dry run) + operation: + initiatedBy: + username: admin + retry: {} + sync: + revision: 6c1a12cdae7ccf40a6ba2282482187045749be6b + syncOptions: + - Replace=true + syncStrategy: + hook: + force: true + phase: Failed + startedAt: "2025-05-08T14:57:16Z" + syncResult: + resources: + - group: batch + hookPhase: Failed + hookType: PreSync + kind: Job + message: 'error when deleting "/dev/shm/4286291675": jobs.batch "ingress-nginx-admission-create" + not found' + name: ingress-nginx-admission-create + namespace: default + status: SyncFailed + syncPhase: PreSync + version: v1 + revision: 6c1a12cdae7ccf40a6ba2282482187045749be6b + source: + path: ingress-nginx + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + reconciledAt: "2025-05-08T14:57:22Z" + resources: + - kind: ConfigMap + name: ingress-nginx-controller + namespace: default + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: ingress-nginx-controller + namespace: default + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: ingress-nginx-controller-admission + namespace: default + status: Synced + version: v1 + - kind: ServiceAccount + name: ingress-nginx + namespace: default + status: Synced + version: v1 + - group: admissionregistration.k8s.io + kind: ValidatingWebhookConfiguration + name: ingress-nginx-admission + status: Synced + version: v1 + - group: apps + health: + status: Healthy + kind: Deployment + name: ingress-nginx-controller + namespace: default + status: Synced + version: v1 + - group: networking.k8s.io + kind: IngressClass + name: nginx + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: ingress-nginx + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRoleBinding + name: ingress-nginx + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: Role + name: ingress-nginx + namespace: default + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: RoleBinding + name: ingress-nginx + namespace: default + status: Synced + version: v1 + sourceType: Helm + summary: + images: + - registry.k8s.io/ingress-nginx/controller:v1.12.2@sha256:03497ee984628e95eca9b2279e3f3a3c1685dd48635479e627d219f00c8eefa9 + sync: + comparedTo: + destination: + server: https://kubernetes.default.svc + source: + path: ingress-nginx + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + revision: 6c1a12cdae7ccf40a6ba2282482187045749be6b + status: Synced diff --git a/argo-infra-apps/kafka.yaml b/argo-infra-apps/kafka.yaml new file mode 100644 index 0000000..434d7af --- /dev/null +++ b/argo-infra-apps/kafka.yaml @@ -0,0 +1,359 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"argoproj.io/v1alpha1","kind":"Application","metadata":{"annotations":{},"creationTimestamp":"2025-03-18T14:44:38Z","generation":557,"labels":{"app.kubernetes.io/instance":"argo-infra-apps"},"name":"kafka","namespace":"argocd","resourceVersion":"424505","uid":"6408196f-c1be-4260-aa77-02b2122a3f43"},"spec":{"destination":{"namespace":"kafka","server":"https://kubernetes.default.svc"},"project":"default","source":{"path":"kafka","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"},"syncPolicy":{"automated":{"prune":true,"selfHeal":true},"syncOptions":["CreateNamespace=true"]}},"status":{"controllerNamespace":"argocd","health":{"status":"Healthy"},"history":[{"deployStartedAt":"2025-03-18T14:44:41Z","deployedAt":"2025-03-18T14:44:44Z","id":0,"initiatedBy":{"automated":true},"revision":"2dbc2c07368f5ace43bbb70938daa99e8b498589","source":{"path":"kafka","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}},{"deployStartedAt":"2025-03-18T17:10:34Z","deployedAt":"2025-03-18T17:10:34Z","id":1,"initiatedBy":{"automated":true},"revision":"f0b5d9ebe0e06180a2425f74ba70882be0cb41ce","source":{"path":"kafka","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}},{"deployStartedAt":"2025-03-19T10:37:36Z","deployedAt":"2025-03-19T10:37:37Z","id":2,"initiatedBy":{"automated":true},"revision":"66c29291453cc31166552c8cfb733467c73d0b33","source":{"path":"kafka","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}},{"deployStartedAt":"2025-03-19T10:58:36Z","deployedAt":"2025-03-19T10:58:37Z","id":3,"initiatedBy":{"automated":true},"revision":"ea003db2768a9cadc1e8a6ca0c9f6368a165243a","source":{"path":"kafka","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}}],"operationState":{"finishedAt":"2025-03-19T10:58:37Z","message":"successfully synced (all tasks run)","operation":{"initiatedBy":{"automated":true},"retry":{"limit":5},"sync":{"prune":true,"revision":"ea003db2768a9cadc1e8a6ca0c9f6368a165243a","syncOptions":["CreateNamespace=true"]}},"phase":"Succeeded","startedAt":"2025-03-19T10:58:36Z","syncResult":{"resources":[{"group":"networking.k8s.io","hookPhase":"Running","kind":"NetworkPolicy","message":"networkpolicy.networking.k8s.io/kafka configured","name":"kafka","namespace":"kafka","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"policy","hookPhase":"Running","kind":"PodDisruptionBudget","message":"poddisruptionbudget.policy/kafka-broker configured","name":"kafka-broker","namespace":"kafka","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"policy","hookPhase":"Running","kind":"PodDisruptionBudget","message":"poddisruptionbudget.policy/kafka-controller configured","name":"kafka-controller","namespace":"kafka","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"ServiceAccount","message":"serviceaccount/kafka unchanged","name":"kafka","namespace":"kafka","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"ServiceAccount","message":"serviceaccount/kafka-provisioning unchanged","name":"kafka-provisioning","namespace":"kafka","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"Secret","message":"secret/kafka-kraft-cluster-id configured","name":"kafka-kraft-cluster-id","namespace":"kafka","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"Secret","message":"secret/kafka-user-passwords configured","name":"kafka-user-passwords","namespace":"kafka","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"ConfigMap","message":"configmap/kafka-controller-configuration unchanged","name":"kafka-controller-configuration","namespace":"kafka","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"ConfigMap","message":"configmap/kafka-scripts unchanged","name":"kafka-scripts","namespace":"kafka","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"Service","message":"service/kafka-controller-headless unchanged","name":"kafka-controller-headless","namespace":"kafka","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"Service","message":"service/kafka configured","name":"kafka","namespace":"kafka","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"autoscaling","hookPhase":"Running","kind":"HorizontalPodAutoscaler","message":"horizontalpodautoscaler.autoscaling/kafka-controller unchanged","name":"kafka-controller","namespace":"kafka","status":"Synced","syncPhase":"Sync","version":"v2"},{"group":"apps","hookPhase":"Running","kind":"StatefulSet","message":"statefulset.apps/kafka-controller configured","name":"kafka-controller","namespace":"kafka","status":"Synced","syncPhase":"Sync","version":"v1"}],"revision":"ea003db2768a9cadc1e8a6ca0c9f6368a165243a","source":{"path":"kafka","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}}},"reconciledAt":"2025-03-19T13:55:34Z","resources":[{"kind":"ConfigMap","name":"kafka-controller-configuration","namespace":"kafka","status":"Synced","version":"v1"},{"kind":"ConfigMap","name":"kafka-scripts","namespace":"kafka","status":"Synced","version":"v1"},{"kind":"Secret","name":"kafka-kraft-cluster-id","namespace":"kafka","status":"Synced","version":"v1"},{"kind":"Secret","name":"kafka-user-passwords","namespace":"kafka","status":"Synced","version":"v1"},{"health":{"status":"Healthy"},"kind":"Service","name":"kafka","namespace":"kafka","status":"Synced","version":"v1"},{"health":{"status":"Healthy"},"kind":"Service","name":"kafka-controller-headless","namespace":"kafka","status":"Synced","version":"v1"},{"kind":"ServiceAccount","name":"kafka","namespace":"kafka","status":"Synced","version":"v1"},{"kind":"ServiceAccount","name":"kafka-provisioning","namespace":"kafka","status":"Synced","version":"v1"},{"group":"apps","health":{"message":"statefulset rolling update complete 3 pods at revision kafka-controller-748799774c...","status":"Healthy"},"kind":"StatefulSet","name":"kafka-controller","namespace":"kafka","status":"Synced","version":"v1"},{"group":"autoscaling","health":{"message":"the HPA controller was able to get the target's current scale","status":"Healthy"},"kind":"HorizontalPodAutoscaler","name":"kafka-controller","namespace":"kafka","status":"Synced","version":"v2"},{"group":"networking.k8s.io","kind":"NetworkPolicy","name":"kafka","namespace":"kafka","status":"Synced","version":"v1"},{"group":"policy","kind":"PodDisruptionBudget","name":"kafka-broker","namespace":"kafka","status":"Synced","version":"v1"},{"group":"policy","kind":"PodDisruptionBudget","name":"kafka-controller","namespace":"kafka","status":"Synced","version":"v1"}],"sourceType":"Helm","summary":{"images":["docker.io/bitnami/kafka:3.9.0-debian-12-r12"]},"sync":{"comparedTo":{"destination":{"namespace":"kafka","server":"https://kubernetes.default.svc"},"source":{"path":"kafka","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}},"revision":"ea003db2768a9cadc1e8a6ca0c9f6368a165243a","status":"Synced"}}} + creationTimestamp: "2025-03-19T14:00:58Z" + generation: 72 + labels: + app.kubernetes.io/instance: argo-infra-apps + name: kafka + namespace: argocd + resourceVersion: "442203" + uid: 742ebfdd-6dd9-4eea-bc4f-075e1f970bf4 +spec: + destination: + namespace: kafka + server: https://kubernetes.default.svc + project: default + source: + path: kafka + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true + ignoreDifferences: + - group: apps + kind: StatefulSet + name: kafka-controller + jsonPointers: + - /spec/template/metadata/annotations + - /status + - group: "" + kind: Secret + name: kafka-kraft-cluster-id + jsonPointers: + - /data + - /metadata/annotations + - group: "" + kind: Secret + name: kafka-user-passwords + jsonPointers: + - /data + - /metadata/annotations +status: + controllerNamespace: argocd + health: + status: Healthy + history: + - deployStartedAt: "2025-03-18T14:44:41Z" + deployedAt: "2025-03-18T14:44:44Z" + id: 0 + initiatedBy: + automated: true + revision: 2dbc2c07368f5ace43bbb70938daa99e8b498589 + source: + path: kafka + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-03-18T17:10:34Z" + deployedAt: "2025-03-18T17:10:34Z" + id: 1 + initiatedBy: + automated: true + revision: f0b5d9ebe0e06180a2425f74ba70882be0cb41ce + source: + path: kafka + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-03-19T10:37:36Z" + deployedAt: "2025-03-19T10:37:37Z" + id: 2 + initiatedBy: + automated: true + revision: 66c29291453cc31166552c8cfb733467c73d0b33 + source: + path: kafka + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-03-19T10:58:36Z" + deployedAt: "2025-03-19T10:58:37Z" + id: 3 + initiatedBy: + automated: true + revision: ea003db2768a9cadc1e8a6ca0c9f6368a165243a + source: + path: kafka + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-03-19T14:01:01Z" + deployedAt: "2025-03-19T14:01:03Z" + id: 4 + initiatedBy: + automated: true + revision: ccbcd028530e5528739ce1fd9d30fa1a835db178 + source: + path: kafka + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-03-19T14:04:38Z" + deployedAt: "2025-03-19T14:04:39Z" + id: 5 + initiatedBy: + automated: true + revision: 170f1d93a41905281cbf22e6e4bd394d1fd57b7f + source: + path: kafka + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-03-19T14:34:38Z" + deployedAt: "2025-03-19T14:34:39Z" + id: 6 + initiatedBy: + automated: true + revision: 51a8196fc681a3e098bb86eb1f2dd0889bfab910 + source: + path: kafka + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + operationState: + finishedAt: "2025-03-19T14:34:39Z" + message: successfully synced (all tasks run) + operation: + initiatedBy: + automated: true + retry: + limit: 5 + sync: + prune: true + revision: 51a8196fc681a3e098bb86eb1f2dd0889bfab910 + syncOptions: + - CreateNamespace=true + phase: Succeeded + startedAt: "2025-03-19T14:34:38Z" + syncResult: + resources: + - group: networking.k8s.io + hookPhase: Running + kind: NetworkPolicy + message: networkpolicy.networking.k8s.io/kafka configured + name: kafka + namespace: kafka + status: Synced + syncPhase: Sync + version: v1 + - group: policy + hookPhase: Running + kind: PodDisruptionBudget + message: poddisruptionbudget.policy/kafka-controller configured + name: kafka-controller + namespace: kafka + status: Synced + syncPhase: Sync + version: v1 + - group: policy + hookPhase: Running + kind: PodDisruptionBudget + message: poddisruptionbudget.policy/kafka-broker configured + name: kafka-broker + namespace: kafka + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: ServiceAccount + message: serviceaccount/kafka-provisioning unchanged + name: kafka-provisioning + namespace: kafka + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: ServiceAccount + message: serviceaccount/kafka unchanged + name: kafka + namespace: kafka + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Secret + message: secret/kafka-kraft-cluster-id configured + name: kafka-kraft-cluster-id + namespace: kafka + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Secret + message: secret/kafka-user-passwords configured + name: kafka-user-passwords + namespace: kafka + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: ConfigMap + message: configmap/kafka-controller-configuration unchanged + name: kafka-controller-configuration + namespace: kafka + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: ConfigMap + message: configmap/kafka-scripts unchanged + name: kafka-scripts + namespace: kafka + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: service/kafka-controller-headless unchanged + name: kafka-controller-headless + namespace: kafka + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: service/kafka configured + name: kafka + namespace: kafka + status: Synced + syncPhase: Sync + version: v1 + - group: autoscaling + hookPhase: Running + kind: HorizontalPodAutoscaler + message: horizontalpodautoscaler.autoscaling/kafka-controller unchanged + name: kafka-controller + namespace: kafka + status: Synced + syncPhase: Sync + version: v2 + - group: apps + hookPhase: Running + kind: StatefulSet + message: statefulset.apps/kafka-controller configured + name: kafka-controller + namespace: kafka + status: Synced + syncPhase: Sync + version: v1 + revision: 51a8196fc681a3e098bb86eb1f2dd0889bfab910 + source: + path: kafka + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + reconciledAt: "2025-03-19T15:34:34Z" + resources: + - kind: ConfigMap + name: kafka-controller-configuration + namespace: kafka + status: Synced + version: v1 + - kind: ConfigMap + name: kafka-scripts + namespace: kafka + status: Synced + version: v1 + - kind: Secret + name: kafka-kraft-cluster-id + namespace: kafka + status: Synced + version: v1 + - kind: Secret + name: kafka-user-passwords + namespace: kafka + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: kafka + namespace: kafka + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: kafka-controller-headless + namespace: kafka + status: Synced + version: v1 + - kind: ServiceAccount + name: kafka + namespace: kafka + status: Synced + version: v1 + - kind: ServiceAccount + name: kafka-provisioning + namespace: kafka + status: Synced + version: v1 + - group: apps + health: + message: statefulset rolling update complete 3 pods at revision kafka-controller-69fd99ccfd... + status: Healthy + kind: StatefulSet + name: kafka-controller + namespace: kafka + status: Synced + version: v1 + - group: autoscaling + health: + message: the HPA controller was able to get the target's current scale + status: Healthy + kind: HorizontalPodAutoscaler + name: kafka-controller + namespace: kafka + status: Synced + version: v2 + - group: networking.k8s.io + kind: NetworkPolicy + name: kafka + namespace: kafka + status: Synced + version: v1 + - group: policy + kind: PodDisruptionBudget + name: kafka-broker + namespace: kafka + status: Synced + version: v1 + - group: policy + kind: PodDisruptionBudget + name: kafka-controller + namespace: kafka + status: Synced + version: v1 + sourceType: Helm + summary: + images: + - docker.io/bitnami/kafka:3.9.0-debian-12-r12 + sync: + comparedTo: + destination: + namespace: kafka + server: https://kubernetes.default.svc + source: + path: kafka + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + revision: 51a8196fc681a3e098bb86eb1f2dd0889bfab910 + status: Synced diff --git a/argo-infra-apps/livekit-egress.yaml b/argo-infra-apps/livekit-egress.yaml new file mode 100644 index 0000000..327fee6 --- /dev/null +++ b/argo-infra-apps/livekit-egress.yaml @@ -0,0 +1,122 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + creationTimestamp: "2025-05-08T14:26:30Z" + generation: 14 + name: livekit-egress + namespace: argocd + resourceVersion: "15428767" + uid: e20642c8-3378-4c0c-8f8f-9c54440413ac +spec: + destination: + namespace: livekit + server: https://kubernetes.default.svc + project: default + source: + path: livekit/livekit-egress + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + syncPolicy: + automated: {} + syncOptions: + - CreateNamespace=true + ignoreDifferences: + - group: apps + kind: Deployment + name: livekit-egress + namespace: livekit + jsonPointers: + - /spec/replicas +status: + controllerNamespace: argocd + health: + status: Healthy + history: + - deployStartedAt: "2025-05-08T14:26:31Z" + deployedAt: "2025-05-08T14:26:34Z" + id: 0 + initiatedBy: + automated: true + revision: c8b0c0149b5392e63bf832f558305d59d82ae9af + source: + path: livekit/livekit-egress + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + operationState: + finishedAt: "2025-05-08T14:26:34Z" + message: successfully synced (all tasks run) + operation: + initiatedBy: + automated: true + retry: + limit: 5 + sync: + revision: c8b0c0149b5392e63bf832f558305d59d82ae9af + syncOptions: + - CreateNamespace=true + phase: Succeeded + startedAt: "2025-05-08T14:26:31Z" + syncResult: + resources: + - group: "" + hookPhase: Running + kind: Namespace + message: namespace/livekit created + name: livekit + namespace: "" + status: Synced + syncPhase: PreSync + version: v1 + - group: "" + hookPhase: Running + kind: ConfigMap + message: configmap/livekit-egress created + name: livekit-egress + namespace: livekit + status: Synced + syncPhase: Sync + version: v1 + - group: apps + hookPhase: Running + kind: Deployment + message: deployment.apps/livekit-egress created + name: livekit-egress + namespace: livekit + status: Synced + syncPhase: Sync + version: v1 + revision: c8b0c0149b5392e63bf832f558305d59d82ae9af + source: + path: livekit/livekit-egress + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + reconciledAt: "2025-05-08T14:35:27Z" + resources: + - kind: ConfigMap + name: livekit-egress + namespace: livekit + status: Synced + version: v1 + - group: apps + health: + status: Healthy + kind: Deployment + name: livekit-egress + namespace: livekit + status: Synced + version: v1 + sourceType: Helm + summary: + images: + - livekit/egress:v1.9.0 + sync: + comparedTo: + destination: + namespace: livekit + server: https://kubernetes.default.svc + source: + path: livekit/livekit-egress + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + revision: c8b0c0149b5392e63bf832f558305d59d82ae9af + status: Synced diff --git a/argo-infra-apps/livekit-server.yaml b/argo-infra-apps/livekit-server.yaml new file mode 100644 index 0000000..1deed39 --- /dev/null +++ b/argo-infra-apps/livekit-server.yaml @@ -0,0 +1,194 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + creationTimestamp: "2025-05-12T19:26:50Z" + generation: 54 + name: livekit-server + namespace: argocd + resourceVersion: "16843936" + uid: 6fd2964a-59c7-442f-8029-d3c7095ee329 +spec: + destination: + namespace: livekit + server: https://kubernetes.default.svc + project: default + source: + path: livekit/livekit-server + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + syncPolicy: + automated: {} + syncOptions: + - CreateNamespace=true + ignoreDifferences: + - group: apps + kind: Deployment + name: livekit-server + namespace: livekit + jsonPointers: + - /spec/replicas + +status: + controllerNamespace: argocd + health: + status: Progressing + history: + - deployStartedAt: "2025-05-12T19:39:24Z" + deployedAt: "2025-05-12T19:39:25Z" + id: 0 + initiatedBy: + username: admin + revision: bd036c064dfb7ad6ff8537ffcbd411e433b899f1 + source: + path: livekit/livekit-server + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + operationState: + finishedAt: "2025-05-12T19:39:25Z" + message: successfully synced (all tasks run) + operation: + initiatedBy: + username: admin + retry: {} + sync: + revision: bd036c064dfb7ad6ff8537ffcbd411e433b899f1 + syncOptions: + - CreateNamespace=true + - Replace=true + syncStrategy: + hook: + force: true + phase: Succeeded + startedAt: "2025-05-12T19:39:24Z" + syncResult: + resources: + - group: "" + hookPhase: Running + kind: ConfigMap + message: |- + configmap "livekit-server" deleted + configmap/livekit-server replaced + name: livekit-server + namespace: livekit + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: |- + service "livekit-server" deleted + service/livekit-server replaced + name: livekit-server + namespace: livekit + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: |- + service "livekit-server-turn" deleted + service/livekit-server-turn replaced + name: livekit-server-turn + namespace: livekit + status: Synced + syncPhase: Sync + version: v1 + - group: apps + hookPhase: Running + kind: Deployment + message: |- + deployment.apps "livekit-server" deleted + deployment.apps/livekit-server replaced + name: livekit-server + namespace: livekit + status: Synced + syncPhase: Sync + version: v1 + - group: networking.k8s.io + hookPhase: Running + kind: Ingress + message: ingress.networking.k8s.io/livekit-server-turn created + name: livekit-server-turn + namespace: livekit + status: Synced + syncPhase: Sync + version: v1 + - group: networking.k8s.io + hookPhase: Running + kind: Ingress + message: ingress.networking.k8s.io/livekit-server created + name: livekit-server + namespace: livekit + status: Synced + syncPhase: Sync + version: v1 + revision: bd036c064dfb7ad6ff8537ffcbd411e433b899f1 + source: + path: livekit/livekit-server + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + reconciledAt: "2025-05-12T20:05:28Z" + resources: + - kind: ConfigMap + name: livekit-server + namespace: livekit + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: livekit-server + namespace: livekit + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: livekit-server-turn + namespace: livekit + status: Synced + version: v1 + - group: apps + health: + status: Healthy + kind: Deployment + name: livekit-server + namespace: livekit + status: Synced + version: v1 + - group: networking.k8s.io + health: + status: Healthy + kind: Ingress + name: livekit-server + namespace: livekit + status: Synced + version: v1 + - group: networking.k8s.io + health: + status: Progressing + kind: Ingress + name: livekit-server-turn + namespace: livekit + status: Synced + version: v1 + sourceType: Helm + summary: + externalURLs: + - https://av-s001.co-work.ru/ + - https://avt-s001.co-work.ru/ + images: + - livekit/livekit-server:v1.8.3 + sync: + comparedTo: + destination: + namespace: livekit + server: https://kubernetes.default.svc + source: + path: livekit/livekit-server + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + revision: bd036c064dfb7ad6ff8537ffcbd411e433b899f1 + status: Synced diff --git a/argo-infra-apps/nfs-subdir-external-provisione.yaml b/argo-infra-apps/nfs-subdir-external-provisione.yaml new file mode 100644 index 0000000..9f0aa50 --- /dev/null +++ b/argo-infra-apps/nfs-subdir-external-provisione.yaml @@ -0,0 +1,233 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"argoproj.io/v1alpha1","kind":"Application","metadata":{"annotations":{},"creationTimestamp":"2025-03-18T14:35:11Z","generation":480,"labels":{"app.kubernetes.io/instance":"argo-infra-apps"},"name":"nfs-subdir-external-provisioner","namespace":"argocd","resourceVersion":"424045","uid":"4eb0dc43-aa4f-4df2-b844-930cb6c7d1de"},"spec":{"destination":{"namespace":"nfs-subdir-external-provisioner","server":"https://kubernetes.default.svc"},"project":"default","source":{"path":"nfs-subdir-external-provisioner","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"},"syncPolicy":{"automated":{"prune":true,"selfHeal":true},"syncOptions":["CreateNamespace=true"]}},"status":{"controllerNamespace":"argocd","health":{"status":"Healthy"},"history":[{"deployStartedAt":"2025-03-18T14:35:15Z","deployedAt":"2025-03-18T14:35:17Z","id":0,"initiatedBy":{"automated":true},"revision":"2dbc2c07368f5ace43bbb70938daa99e8b498589","source":{"path":"nfs-subdir-external-provisioner","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}}],"operationState":{"finishedAt":"2025-03-18T14:35:18Z","message":"successfully synced (all tasks run)","operation":{"initiatedBy":{"automated":true},"retry":{"limit":5},"sync":{"prune":true,"revision":"2dbc2c07368f5ace43bbb70938daa99e8b498589","syncOptions":["CreateNamespace=true"]}},"phase":"Succeeded","startedAt":"2025-03-18T14:35:15Z","syncResult":{"resources":[{"group":"","hookPhase":"Running","kind":"Namespace","message":"namespace/nfs-subdir-external-provisioner created","name":"nfs-subdir-external-provisioner","namespace":"","status":"Synced","syncPhase":"PreSync","version":"v1"},{"group":"","hookPhase":"Running","kind":"ServiceAccount","message":"serviceaccount/nfs-subdir-external-provisioner created","name":"nfs-subdir-external-provisioner","namespace":"nfs-subdir-external-provisioner","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"storage.k8s.io","hookPhase":"Running","kind":"StorageClass","message":"storageclass.storage.k8s.io/nfs-client created","name":"nfs-client","namespace":"nfs-subdir-external-provisioner","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"rbac.authorization.k8s.io","hookPhase":"Running","kind":"ClusterRole","message":"clusterrole.rbac.authorization.k8s.io/nfs-subdir-external-provisioner-runner reconciled. reconciliation required create\n\tmissing rules added:\n\t\t{Verbs:[get list watch] APIGroups:[] Resources:[nodes] ResourceNames:[] NonResourceURLs:[]}\n\t\t{Verbs:[get list watch create delete] APIGroups:[] Resources:[persistentvolumes] ResourceNames:[] NonResourceURLs:[]}\n\t\t{Verbs:[get list watch update] APIGroups:[] Resources:[persistentvolumeclaims] ResourceNames:[] NonResourceURLs:[]}\n\t\t{Verbs:[get list watch] APIGroups:[storage.k8s.io] Resources:[storageclasses] ResourceNames:[] NonResourceURLs:[]}\n\t\t{Verbs:[create update patch] APIGroups:[] Resources:[events] ResourceNames:[] NonResourceURLs:[]}. clusterrole.rbac.authorization.k8s.io/nfs-subdir-external-provisioner-runner configured. Warning: resource clusterroles/nfs-subdir-external-provisioner-runner is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by apply. apply should only be used on resources created declaratively by either create --save-config or apply. The missing annotation will be patched automatically.","name":"nfs-subdir-external-provisioner-runner","namespace":"nfs-subdir-external-provisioner","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"rbac.authorization.k8s.io","hookPhase":"Running","kind":"ClusterRoleBinding","message":"clusterrolebinding.rbac.authorization.k8s.io/run-nfs-subdir-external-provisioner reconciled. reconciliation required create\n\tmissing subjects added:\n\t\t{Kind:ServiceAccount APIGroup: Name:nfs-subdir-external-provisioner Namespace:nfs-subdir-external-provisioner}. clusterrolebinding.rbac.authorization.k8s.io/run-nfs-subdir-external-provisioner configured. Warning: resource clusterrolebindings/run-nfs-subdir-external-provisioner is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by apply. apply should only be used on resources created declaratively by either create --save-config or apply. The missing annotation will be patched automatically.","name":"run-nfs-subdir-external-provisioner","namespace":"nfs-subdir-external-provisioner","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"rbac.authorization.k8s.io","hookPhase":"Running","kind":"Role","message":"role.rbac.authorization.k8s.io/leader-locking-nfs-subdir-external-provisioner reconciled. reconciliation required create\n\tmissing rules added:\n\t\t{Verbs:[get list watch create update patch] APIGroups:[] Resources:[endpoints] ResourceNames:[] NonResourceURLs:[]}. role.rbac.authorization.k8s.io/leader-locking-nfs-subdir-external-provisioner configured. Warning: resource roles/leader-locking-nfs-subdir-external-provisioner is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by apply. apply should only be used on resources created declaratively by either create --save-config or apply. The missing annotation will be patched automatically.","name":"leader-locking-nfs-subdir-external-provisioner","namespace":"nfs-subdir-external-provisioner","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"rbac.authorization.k8s.io","hookPhase":"Running","kind":"RoleBinding","message":"rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-subdir-external-provisioner reconciled. reconciliation required create\n\tmissing subjects added:\n\t\t{Kind:ServiceAccount APIGroup: Name:nfs-subdir-external-provisioner Namespace:nfs-subdir-external-provisioner}. rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-subdir-external-provisioner configured. Warning: resource rolebindings/leader-locking-nfs-subdir-external-provisioner is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by apply. apply should only be used on resources created declaratively by either create --save-config or apply. The missing annotation will be patched automatically.","name":"leader-locking-nfs-subdir-external-provisioner","namespace":"nfs-subdir-external-provisioner","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"apps","hookPhase":"Running","kind":"Deployment","message":"deployment.apps/nfs-subdir-external-provisioner created","name":"nfs-subdir-external-provisioner","namespace":"nfs-subdir-external-provisioner","status":"Synced","syncPhase":"Sync","version":"v1"}],"revision":"2dbc2c07368f5ace43bbb70938daa99e8b498589","source":{"path":"nfs-subdir-external-provisioner","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}}},"reconciledAt":"2025-03-19T13:52:34Z","resources":[{"kind":"ServiceAccount","name":"nfs-subdir-external-provisioner","namespace":"nfs-subdir-external-provisioner","status":"Synced","version":"v1"},{"group":"apps","health":{"status":"Healthy"},"kind":"Deployment","name":"nfs-subdir-external-provisioner","namespace":"nfs-subdir-external-provisioner","status":"Synced","version":"v1"},{"group":"rbac.authorization.k8s.io","kind":"ClusterRole","name":"nfs-subdir-external-provisioner-runner","status":"Synced","version":"v1"},{"group":"rbac.authorization.k8s.io","kind":"ClusterRoleBinding","name":"run-nfs-subdir-external-provisioner","status":"Synced","version":"v1"},{"group":"rbac.authorization.k8s.io","kind":"Role","name":"leader-locking-nfs-subdir-external-provisioner","namespace":"nfs-subdir-external-provisioner","status":"Synced","version":"v1"},{"group":"rbac.authorization.k8s.io","kind":"RoleBinding","name":"leader-locking-nfs-subdir-external-provisioner","namespace":"nfs-subdir-external-provisioner","status":"Synced","version":"v1"},{"group":"storage.k8s.io","kind":"StorageClass","name":"nfs-client","status":"Synced","version":"v1"}],"sourceType":"Helm","summary":{"images":["registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2"]},"sync":{"comparedTo":{"destination":{"namespace":"nfs-subdir-external-provisioner","server":"https://kubernetes.default.svc"},"source":{"path":"nfs-subdir-external-provisioner","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}},"revision":"ea003db2768a9cadc1e8a6ca0c9f6368a165243a","status":"Synced"}}} + creationTimestamp: "2025-03-19T14:00:58Z" + generation: 45 + labels: + app.kubernetes.io/instance: argo-infra-apps + name: nfs-subdir-external-provisioner + namespace: argocd + resourceVersion: "442199" + uid: 46da0f9d-0b3b-4b16-ab5d-ef5d65b15792 +spec: + destination: + namespace: nfs-subdir-external-provisioner + server: https://kubernetes.default.svc + project: default + source: + path: nfs-subdir-external-provisioner + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true +status: + controllerNamespace: argocd + health: + status: Healthy + history: + - deployStartedAt: "2025-03-18T14:35:15Z" + deployedAt: "2025-03-18T14:35:17Z" + id: 0 + initiatedBy: + automated: true + revision: 2dbc2c07368f5ace43bbb70938daa99e8b498589 + source: + path: nfs-subdir-external-provisioner + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-03-19T14:01:00Z" + deployedAt: "2025-03-19T14:01:02Z" + id: 1 + initiatedBy: + automated: true + revision: ccbcd028530e5528739ce1fd9d30fa1a835db178 + source: + path: nfs-subdir-external-provisioner + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + operationState: + finishedAt: "2025-03-19T14:01:02Z" + message: successfully synced (all tasks run) + operation: + initiatedBy: + automated: true + retry: + limit: 5 + sync: + prune: true + revision: ccbcd028530e5528739ce1fd9d30fa1a835db178 + syncOptions: + - CreateNamespace=true + phase: Succeeded + startedAt: "2025-03-19T14:01:00Z" + syncResult: + resources: + - group: "" + hookPhase: Running + kind: ServiceAccount + message: serviceaccount/nfs-subdir-external-provisioner created + name: nfs-subdir-external-provisioner + namespace: nfs-subdir-external-provisioner + status: Synced + syncPhase: Sync + version: v1 + - group: storage.k8s.io + hookPhase: Running + kind: StorageClass + message: storageclass.storage.k8s.io/nfs-client created + name: nfs-client + namespace: nfs-subdir-external-provisioner + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: "clusterrole.rbac.authorization.k8s.io/nfs-subdir-external-provisioner-runner + reconciled. reconciliation required create\n\tmissing rules added:\n\t\t{Verbs:[get + list watch] APIGroups:[] Resources:[nodes] ResourceNames:[] NonResourceURLs:[]}\n\t\t{Verbs:[get + list watch create delete] APIGroups:[] Resources:[persistentvolumes] ResourceNames:[] + NonResourceURLs:[]}\n\t\t{Verbs:[get list watch update] APIGroups:[] Resources:[persistentvolumeclaims] + ResourceNames:[] NonResourceURLs:[]}\n\t\t{Verbs:[get list watch] APIGroups:[storage.k8s.io] + Resources:[storageclasses] ResourceNames:[] NonResourceURLs:[]}\n\t\t{Verbs:[create + update patch] APIGroups:[] Resources:[events] ResourceNames:[] NonResourceURLs:[]}. + clusterrole.rbac.authorization.k8s.io/nfs-subdir-external-provisioner-runner + configured. Warning: resource clusterroles/nfs-subdir-external-provisioner-runner + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically." + name: nfs-subdir-external-provisioner-runner + namespace: nfs-subdir-external-provisioner + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRoleBinding + message: "clusterrolebinding.rbac.authorization.k8s.io/run-nfs-subdir-external-provisioner + reconciled. reconciliation required create\n\tmissing subjects added:\n\t\t{Kind:ServiceAccount + APIGroup: Name:nfs-subdir-external-provisioner Namespace:nfs-subdir-external-provisioner}. + clusterrolebinding.rbac.authorization.k8s.io/run-nfs-subdir-external-provisioner + configured. Warning: resource clusterrolebindings/run-nfs-subdir-external-provisioner + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically." + name: run-nfs-subdir-external-provisioner + namespace: nfs-subdir-external-provisioner + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: Role + message: "role.rbac.authorization.k8s.io/leader-locking-nfs-subdir-external-provisioner + reconciled. reconciliation required create\n\tmissing rules added:\n\t\t{Verbs:[get + list watch create update patch] APIGroups:[] Resources:[endpoints] ResourceNames:[] + NonResourceURLs:[]}. role.rbac.authorization.k8s.io/leader-locking-nfs-subdir-external-provisioner + configured. Warning: resource roles/leader-locking-nfs-subdir-external-provisioner + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically." + name: leader-locking-nfs-subdir-external-provisioner + namespace: nfs-subdir-external-provisioner + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: RoleBinding + message: "rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-subdir-external-provisioner + reconciled. reconciliation required create\n\tmissing subjects added:\n\t\t{Kind:ServiceAccount + APIGroup: Name:nfs-subdir-external-provisioner Namespace:nfs-subdir-external-provisioner}. + rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-subdir-external-provisioner + configured. Warning: resource rolebindings/leader-locking-nfs-subdir-external-provisioner + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically." + name: leader-locking-nfs-subdir-external-provisioner + namespace: nfs-subdir-external-provisioner + status: Synced + syncPhase: Sync + version: v1 + - group: apps + hookPhase: Running + kind: Deployment + message: deployment.apps/nfs-subdir-external-provisioner created + name: nfs-subdir-external-provisioner + namespace: nfs-subdir-external-provisioner + status: Synced + syncPhase: Sync + version: v1 + revision: ccbcd028530e5528739ce1fd9d30fa1a835db178 + source: + path: nfs-subdir-external-provisioner + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + reconciledAt: "2025-03-19T15:34:34Z" + resources: + - kind: ServiceAccount + name: nfs-subdir-external-provisioner + namespace: nfs-subdir-external-provisioner + status: Synced + version: v1 + - group: apps + health: + status: Healthy + kind: Deployment + name: nfs-subdir-external-provisioner + namespace: nfs-subdir-external-provisioner + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: nfs-subdir-external-provisioner-runner + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRoleBinding + name: run-nfs-subdir-external-provisioner + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: Role + name: leader-locking-nfs-subdir-external-provisioner + namespace: nfs-subdir-external-provisioner + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: RoleBinding + name: leader-locking-nfs-subdir-external-provisioner + namespace: nfs-subdir-external-provisioner + status: Synced + version: v1 + - group: storage.k8s.io + kind: StorageClass + name: nfs-client + status: Synced + version: v1 + sourceType: Helm + summary: + images: + - registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2 + sync: + comparedTo: + destination: + namespace: nfs-subdir-external-provisioner + server: https://kubernetes.default.svc + source: + path: nfs-subdir-external-provisioner + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + revision: 51a8196fc681a3e098bb86eb1f2dd0889bfab910 + status: Synced diff --git a/argo-infra-apps/postgres.yaml b/argo-infra-apps/postgres.yaml new file mode 100644 index 0000000..27aea20 --- /dev/null +++ b/argo-infra-apps/postgres.yaml @@ -0,0 +1,206 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + creationTimestamp: "2025-04-22T07:02:15Z" + generation: 73 + name: postgres + namespace: argocd + resourceVersion: "9726026" + uid: 1fa87c44-6c12-4c29-a67d-d14db049a836 +spec: + destination: + namespace: postgresql + server: https://kubernetes.default.svc + project: default + source: + path: postgresql + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true +status: + controllerNamespace: argocd + health: + status: Healthy + history: + - deployStartedAt: "2025-04-22T07:02:18Z" + deployedAt: "2025-04-22T07:02:22Z" + id: 0 + initiatedBy: + automated: true + revision: 3bb4328927c2b211878533c8928b9aa50d3cb545 + source: + path: postgresql + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-04-22T09:24:50Z" + deployedAt: "2025-04-22T09:24:51Z" + id: 1 + initiatedBy: + automated: true + revision: 70dfc9595b1a8138455d9225facc018518da5e8a + source: + path: postgresql + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-04-22T09:30:49Z" + deployedAt: "2025-04-22T09:30:49Z" + id: 2 + initiatedBy: + automated: true + revision: 411b0b9894242dca75f4ee170a81ceef4e635b0a + source: + path: postgresql + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + operationState: + finishedAt: "2025-04-22T09:30:49Z" + message: successfully synced (all tasks run) + operation: + initiatedBy: + automated: true + retry: + limit: 5 + sync: + prune: true + revision: 411b0b9894242dca75f4ee170a81ceef4e635b0a + syncOptions: + - CreateNamespace=true + phase: Succeeded + startedAt: "2025-04-22T09:30:49Z" + syncResult: + resources: + - group: networking.k8s.io + hookPhase: Running + kind: NetworkPolicy + message: networkpolicy.networking.k8s.io/postgres-postgresql configured + name: postgres-postgresql + namespace: postgresql + status: Synced + syncPhase: Sync + version: v1 + - group: policy + hookPhase: Running + kind: PodDisruptionBudget + message: poddisruptionbudget.policy/postgres-postgresql configured + name: postgres-postgresql + namespace: postgresql + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: ServiceAccount + message: serviceaccount/postgres-postgresql unchanged + name: postgres-postgresql + namespace: postgresql + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Secret + message: secret/postgres-postgresql configured + name: postgres-postgresql + namespace: postgresql + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: service/postgres-postgresql-hl unchanged + name: postgres-postgresql-hl + namespace: postgresql + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: service/postgres-postgresql configured + name: postgres-postgresql + namespace: postgresql + status: Synced + syncPhase: Sync + version: v1 + - group: apps + hookPhase: Running + kind: StatefulSet + message: statefulset.apps/postgres-postgresql configured + name: postgres-postgresql + namespace: postgresql + status: Synced + syncPhase: Sync + version: v1 + revision: 411b0b9894242dca75f4ee170a81ceef4e635b0a + source: + path: postgresql + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + reconciledAt: "2025-04-22T09:36:48Z" + resources: + - kind: Secret + name: postgres-postgresql + namespace: postgresql + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: postgres-postgresql + namespace: postgresql + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: postgres-postgresql-hl + namespace: postgresql + status: Synced + version: v1 + - kind: ServiceAccount + name: postgres-postgresql + namespace: postgresql + status: Synced + version: v1 + - group: apps + health: + message: 'partitioned roll out complete: 1 new pods have been updated...' + status: Healthy + kind: StatefulSet + name: postgres-postgresql + namespace: postgresql + status: Synced + version: v1 + - group: networking.k8s.io + kind: NetworkPolicy + name: postgres-postgresql + namespace: postgresql + status: Synced + version: v1 + - group: policy + kind: PodDisruptionBudget + name: postgres-postgresql + namespace: postgresql + status: Synced + version: v1 + sourceType: Helm + summary: + images: + - docker.io/bitnami/postgresql:17.4.0-debian-12-r15 + sync: + comparedTo: + destination: + namespace: postgresql + server: https://kubernetes.default.svc + source: + path: postgresql + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + revision: 411b0b9894242dca75f4ee170a81ceef4e635b0a + status: Synced diff --git a/argo-infra-apps/postgresql-ha.yaml b/argo-infra-apps/postgresql-ha.yaml new file mode 100644 index 0000000..c1547d3 --- /dev/null +++ b/argo-infra-apps/postgresql-ha.yaml @@ -0,0 +1,20 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: postgresql-ha + namespace: argocd +spec: + project: default + source: + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + path: postgresql-ha + destination: + server: https://kubernetes.default.svc + namespace: postgresql-ha + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true diff --git a/argo-infra-apps/redis.yaml b/argo-infra-apps/redis.yaml new file mode 100644 index 0000000..ef2ec7b --- /dev/null +++ b/argo-infra-apps/redis.yaml @@ -0,0 +1,287 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + creationTimestamp: "2025-04-30T20:40:28Z" + generation: 16 + name: redis + namespace: argocd + resourceVersion: "12737426" + uid: e79154a8-6a82-4993-8479-4260dd93deea +spec: + destination: + namespace: redis + server: https://kubernetes.default.svc + project: default + source: + path: redis + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + syncPolicy: + automated: + prune: true + selfHeal: true +status: + controllerNamespace: argocd + health: + status: Healthy + history: + - deployStartedAt: "2025-04-30T20:40:28Z" + deployedAt: "2025-04-30T20:40:29Z" + id: 0 + initiatedBy: + automated: true + revision: d7952823366ef593ddd14f398cd8757fabc1b83a + source: + path: redis + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + operationState: + finishedAt: "2025-04-30T20:40:29Z" + message: successfully synced (all tasks run) + operation: + initiatedBy: + automated: true + retry: + limit: 5 + sync: + prune: true + revision: d7952823366ef593ddd14f398cd8757fabc1b83a + phase: Succeeded + startedAt: "2025-04-30T20:40:28Z" + syncResult: + resources: + - group: networking.k8s.io + hookPhase: Running + kind: NetworkPolicy + message: networkpolicy.networking.k8s.io/redis created + name: redis + namespace: redis + status: Synced + syncPhase: Sync + version: v1 + - group: policy + hookPhase: Running + kind: PodDisruptionBudget + message: poddisruptionbudget.policy/redis-master created + name: redis-master + namespace: redis + status: Synced + syncPhase: Sync + version: v1 + - group: policy + hookPhase: Running + kind: PodDisruptionBudget + message: poddisruptionbudget.policy/redis-replicas created + name: redis-replicas + namespace: redis + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: ServiceAccount + message: serviceaccount/redis-master created + name: redis-master + namespace: redis + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: ServiceAccount + message: serviceaccount/redis-replica created + name: redis-replica + namespace: redis + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Secret + message: secret/redis created + name: redis + namespace: redis + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: ConfigMap + message: configmap/redis-scripts created + name: redis-scripts + namespace: redis + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: ConfigMap + message: configmap/redis-configuration created + name: redis-configuration + namespace: redis + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: ConfigMap + message: configmap/redis-health created + name: redis-health + namespace: redis + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: service/redis-master created + name: redis-master + namespace: redis + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: service/redis-headless created + name: redis-headless + namespace: redis + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: service/redis-replicas created + name: redis-replicas + namespace: redis + status: Synced + syncPhase: Sync + version: v1 + - group: apps + hookPhase: Running + kind: StatefulSet + message: statefulset.apps/redis-master created + name: redis-master + namespace: redis + status: Synced + syncPhase: Sync + version: v1 + - group: apps + hookPhase: Running + kind: StatefulSet + message: statefulset.apps/redis-replicas created + name: redis-replicas + namespace: redis + status: Synced + syncPhase: Sync + version: v1 + revision: d7952823366ef593ddd14f398cd8757fabc1b83a + source: + path: redis + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + reconciledAt: "2025-04-30T20:40:29Z" + resources: + - kind: ConfigMap + name: redis-configuration + namespace: redis + status: Synced + version: v1 + - kind: ConfigMap + name: redis-health + namespace: redis + status: Synced + version: v1 + - kind: ConfigMap + name: redis-scripts + namespace: redis + status: Synced + version: v1 + - kind: Secret + name: redis + namespace: redis + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: redis-headless + namespace: redis + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: redis-master + namespace: redis + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: redis-replicas + namespace: redis + status: Synced + version: v1 + - kind: ServiceAccount + name: redis-master + namespace: redis + status: Synced + version: v1 + - kind: ServiceAccount + name: redis-replica + namespace: redis + status: Synced + version: v1 + - group: apps + health: + message: statefulset rolling update complete 1 pods at revision redis-master-7989dc744c... + status: Healthy + kind: StatefulSet + name: redis-master + namespace: redis + status: Synced + version: v1 + - group: apps + health: + message: statefulset rolling update complete 3 pods at revision redis-replicas-58784fcb67... + status: Healthy + kind: StatefulSet + name: redis-replicas + namespace: redis + status: Synced + version: v1 + - group: networking.k8s.io + kind: NetworkPolicy + name: redis + namespace: redis + status: Synced + version: v1 + - group: policy + kind: PodDisruptionBudget + name: redis-master + namespace: redis + status: Synced + version: v1 + - group: policy + kind: PodDisruptionBudget + name: redis-replicas + namespace: redis + status: Synced + version: v1 + sourceType: Helm + summary: + images: + - docker.io/bitnami/redis:7.4.3-debian-12-r0 + sync: + comparedTo: + destination: + namespace: redis + server: https://kubernetes.default.svc + source: + path: redis + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + revision: d7952823366ef593ddd14f398cd8757fabc1b83a + status: Synced diff --git a/argo-infra-apps/vault-secrets-operator.yaml b/argo-infra-apps/vault-secrets-operator.yaml new file mode 100644 index 0000000..9942013 --- /dev/null +++ b/argo-infra-apps/vault-secrets-operator.yaml @@ -0,0 +1,908 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + creationTimestamp: "2025-03-31T11:53:35Z" + generation: 16 + name: vault-secrets-operator + namespace: argocd + resourceVersion: "3238059" + uid: 0acb50cc-b736-4760-aa60-b1dffc497fdd +spec: + destination: + namespace: vault-secrets-operator + server: https://kubernetes.default.svc + project: default + source: + path: vault-secrets-operator + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true +status: + controllerNamespace: argocd + health: + status: Healthy + history: + - deployStartedAt: "2025-03-31T11:53:37Z" + deployedAt: "2025-03-31T11:53:47Z" + id: 0 + initiatedBy: + automated: true + revision: c44295c14ed484dd4417f4f0ac0a0408aa1d33df + source: + path: vault-secrets-operator + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + operationState: + finishedAt: "2025-03-31T11:53:47Z" + message: successfully synced (all tasks run) + operation: + initiatedBy: + automated: true + retry: + limit: 5 + sync: + prune: true + revision: c44295c14ed484dd4417f4f0ac0a0408aa1d33df + syncOptions: + - CreateNamespace=true + phase: Succeeded + startedAt: "2025-03-31T11:53:37Z" + syncResult: + resources: + - group: "" + hookPhase: Succeeded + hookType: PreSync + kind: ServiceAccount + message: vault-secrets-operator-upgrade-crds created + name: vault-secrets-operator-upgrade-crds + namespace: vault-secrets-operator + syncPhase: PreSync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Succeeded + hookType: PreSync + kind: ClusterRole + message: vault-secrets-operator-upgrade-crds created + name: vault-secrets-operator-upgrade-crds + namespace: vault-secrets-operator + syncPhase: PreSync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Succeeded + hookType: PreSync + kind: ClusterRoleBinding + message: vault-secrets-operator-upgrade-crds created + name: vault-secrets-operator-upgrade-crds + namespace: vault-secrets-operator + syncPhase: PreSync + version: v1 + - group: batch + hookPhase: Succeeded + hookType: PreSync + kind: Job + message: Reached expected number of succeeded pods + name: upgrade-crds-vault-secrets-operator + namespace: vault-secrets-operator + syncPhase: PreSync + version: v1 + - group: "" + hookPhase: Running + kind: ServiceAccount + message: 'serviceaccount/vault-secrets-operator-controller-manager configured. + Warning: resource serviceaccounts/vault-secrets-operator-controller-manager + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-controller-manager + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: ConfigMap + message: 'configmap/vault-secrets-operator-manager-config configured. Warning: + resource configmaps/vault-secrets-operator-manager-config is missing the + kubectl.kubernetes.io/last-applied-configuration annotation which is required + by apply. apply should only be used on resources created declaratively + by either create --save-config or apply. The missing annotation will be + patched automatically.' + name: vault-secrets-operator-manager-config + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: apiextensions.k8s.io + hookPhase: Running + kind: CustomResourceDefinition + message: 'customresourcedefinition.apiextensions.k8s.io/vaultconnections.secrets.hashicorp.com + configured. Warning: resource customresourcedefinitions/vaultconnections.secrets.hashicorp.com + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vaultconnections.secrets.hashicorp.com + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: apiextensions.k8s.io + hookPhase: Running + kind: CustomResourceDefinition + message: 'customresourcedefinition.apiextensions.k8s.io/vaultdynamicsecrets.secrets.hashicorp.com + configured. Warning: resource customresourcedefinitions/vaultdynamicsecrets.secrets.hashicorp.com + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vaultdynamicsecrets.secrets.hashicorp.com + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: apiextensions.k8s.io + hookPhase: Running + kind: CustomResourceDefinition + message: 'customresourcedefinition.apiextensions.k8s.io/vaultauths.secrets.hashicorp.com + configured. Warning: resource customresourcedefinitions/vaultauths.secrets.hashicorp.com + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vaultauths.secrets.hashicorp.com + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: apiextensions.k8s.io + hookPhase: Running + kind: CustomResourceDefinition + message: 'customresourcedefinition.apiextensions.k8s.io/hcpauths.secrets.hashicorp.com + configured. Warning: resource customresourcedefinitions/hcpauths.secrets.hashicorp.com + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: hcpauths.secrets.hashicorp.com + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: apiextensions.k8s.io + hookPhase: Running + kind: CustomResourceDefinition + message: 'customresourcedefinition.apiextensions.k8s.io/hcpvaultsecretsapps.secrets.hashicorp.com + configured. Warning: resource customresourcedefinitions/hcpvaultsecretsapps.secrets.hashicorp.com + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: hcpvaultsecretsapps.secrets.hashicorp.com + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: apiextensions.k8s.io + hookPhase: Running + kind: CustomResourceDefinition + message: 'customresourcedefinition.apiextensions.k8s.io/secrettransformations.secrets.hashicorp.com + configured. Warning: resource customresourcedefinitions/secrettransformations.secrets.hashicorp.com + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: secrettransformations.secrets.hashicorp.com + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: apiextensions.k8s.io + hookPhase: Running + kind: CustomResourceDefinition + message: 'customresourcedefinition.apiextensions.k8s.io/vaultstaticsecrets.secrets.hashicorp.com + configured. Warning: resource customresourcedefinitions/vaultstaticsecrets.secrets.hashicorp.com + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vaultstaticsecrets.secrets.hashicorp.com + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: apiextensions.k8s.io + hookPhase: Running + kind: CustomResourceDefinition + message: 'customresourcedefinition.apiextensions.k8s.io/vaultauthglobals.secrets.hashicorp.com + configured. Warning: resource customresourcedefinitions/vaultauthglobals.secrets.hashicorp.com + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vaultauthglobals.secrets.hashicorp.com + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: apiextensions.k8s.io + hookPhase: Running + kind: CustomResourceDefinition + message: 'customresourcedefinition.apiextensions.k8s.io/vaultpkisecrets.secrets.hashicorp.com + configured. Warning: resource customresourcedefinitions/vaultpkisecrets.secrets.hashicorp.com + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vaultpkisecrets.secrets.hashicorp.com + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-hcpsecretsapp-editor-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-hcpsecretsapp-editor-role + configured. Warning: resource clusterroles/vault-secrets-operator-hcpsecretsapp-editor-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-hcpsecretsapp-editor-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultdynamicsecret-editor-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultdynamicsecret-editor-role + configured. Warning: resource clusterroles/vault-secrets-operator-vaultdynamicsecret-editor-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-vaultdynamicsecret-editor-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultconnection-viewer-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultconnection-viewer-role + configured. Warning: resource clusterroles/vault-secrets-operator-vaultconnection-viewer-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-vaultconnection-viewer-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-secrettransformation-editor-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-secrettransformation-editor-role + configured. Warning: resource clusterroles/vault-secrets-operator-secrettransformation-editor-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-secrettransformation-editor-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-proxy-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-proxy-role + configured. Warning: resource clusterroles/vault-secrets-operator-proxy-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-proxy-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultdynamicsecret-viewer-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultdynamicsecret-viewer-role + configured. Warning: resource clusterroles/vault-secrets-operator-vaultdynamicsecret-viewer-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-vaultdynamicsecret-viewer-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultconnection-editor-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultconnection-editor-role + configured. Warning: resource clusterroles/vault-secrets-operator-vaultconnection-editor-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-vaultconnection-editor-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-manager-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-manager-role + configured. Warning: resource clusterroles/vault-secrets-operator-manager-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-manager-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-hcpauth-editor-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-hcpauth-editor-role + configured. Warning: resource clusterroles/vault-secrets-operator-hcpauth-editor-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-hcpauth-editor-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultstaticsecret-viewer-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultstaticsecret-viewer-role + configured. Warning: resource clusterroles/vault-secrets-operator-vaultstaticsecret-viewer-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-vaultstaticsecret-viewer-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-secrettransformation-viewer-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-secrettransformation-viewer-role + configured. Warning: resource clusterroles/vault-secrets-operator-secrettransformation-viewer-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-secrettransformation-viewer-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultpki-viewer-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultpki-viewer-role + configured. Warning: resource clusterroles/vault-secrets-operator-vaultpki-viewer-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-vaultpki-viewer-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-hcpauth-viewer-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-hcpauth-viewer-role + configured. Warning: resource clusterroles/vault-secrets-operator-hcpauth-viewer-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-hcpauth-viewer-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-hcpsecretsapp-viewer-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-hcpsecretsapp-viewer-role + configured. Warning: resource clusterroles/vault-secrets-operator-hcpsecretsapp-viewer-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-hcpsecretsapp-viewer-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultauthglobal-viewer-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultauthglobal-viewer-role + configured. Warning: resource clusterroles/vault-secrets-operator-vaultauthglobal-viewer-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-vaultauthglobal-viewer-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultauthglobal-editor-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultauthglobal-editor-role + configured. Warning: resource clusterroles/vault-secrets-operator-vaultauthglobal-editor-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-vaultauthglobal-editor-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultpki-editor-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultpki-editor-role + configured. Warning: resource clusterroles/vault-secrets-operator-vaultpki-editor-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-vaultpki-editor-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultauth-viewer-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultauth-viewer-role + configured. Warning: resource clusterroles/vault-secrets-operator-vaultauth-viewer-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-vaultauth-viewer-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultstaticsecret-editor-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultstaticsecret-editor-role + configured. Warning: resource clusterroles/vault-secrets-operator-vaultstaticsecret-editor-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-vaultstaticsecret-editor-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultauth-editor-role + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-vaultauth-editor-role + configured. Warning: resource clusterroles/vault-secrets-operator-vaultauth-editor-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-vaultauth-editor-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: 'clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-metrics-reader + reconciled. clusterrole.rbac.authorization.k8s.io/vault-secrets-operator-metrics-reader + configured. Warning: resource clusterroles/vault-secrets-operator-metrics-reader + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-metrics-reader + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRoleBinding + message: 'clusterrolebinding.rbac.authorization.k8s.io/vault-secrets-operator-proxy-rolebinding + reconciled. clusterrolebinding.rbac.authorization.k8s.io/vault-secrets-operator-proxy-rolebinding + configured. Warning: resource clusterrolebindings/vault-secrets-operator-proxy-rolebinding + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-proxy-rolebinding + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRoleBinding + message: 'clusterrolebinding.rbac.authorization.k8s.io/vault-secrets-operator-manager-rolebinding + reconciled. clusterrolebinding.rbac.authorization.k8s.io/vault-secrets-operator-manager-rolebinding + configured. Warning: resource clusterrolebindings/vault-secrets-operator-manager-rolebinding + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-manager-rolebinding + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: Role + message: 'role.rbac.authorization.k8s.io/vault-secrets-operator-leader-election-role + reconciled. role.rbac.authorization.k8s.io/vault-secrets-operator-leader-election-role + configured. Warning: resource roles/vault-secrets-operator-leader-election-role + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-leader-election-role + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: RoleBinding + message: 'rolebinding.rbac.authorization.k8s.io/vault-secrets-operator-leader-election-rolebinding + reconciled. rolebinding.rbac.authorization.k8s.io/vault-secrets-operator-leader-election-rolebinding + configured. Warning: resource rolebindings/vault-secrets-operator-leader-election-rolebinding + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-leader-election-rolebinding + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: 'service/vault-secrets-operator-metrics-service configured. Warning: + resource services/vault-secrets-operator-metrics-service is missing the + kubectl.kubernetes.io/last-applied-configuration annotation which is required + by apply. apply should only be used on resources created declaratively + by either create --save-config or apply. The missing annotation will be + patched automatically.' + name: vault-secrets-operator-metrics-service + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: apps + hookPhase: Running + kind: Deployment + message: 'deployment.apps/vault-secrets-operator-controller-manager configured. + Warning: resource deployments/vault-secrets-operator-controller-manager + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-controller-manager + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1 + - group: secrets.hashicorp.com + hookPhase: Running + kind: VaultConnection + message: 'vaultconnection.secrets.hashicorp.com/default configured. Warning: + resource vaultconnections/default is missing the kubectl.kubernetes.io/last-applied-configuration + annotation which is required by apply. apply should only be used on resources + created declaratively by either create --save-config or apply. The missing + annotation will be patched automatically.' + name: default + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1beta1 + - group: secrets.hashicorp.com + hookPhase: Running + kind: VaultAuth + message: 'vaultauth.secrets.hashicorp.com/vault-secrets-operator-default-transit-auth + configured. Warning: resource vaultauths/vault-secrets-operator-default-transit-auth + is missing the kubectl.kubernetes.io/last-applied-configuration annotation + which is required by apply. apply should only be used on resources created + declaratively by either create --save-config or apply. The missing annotation + will be patched automatically.' + name: vault-secrets-operator-default-transit-auth + namespace: vault-secrets-operator + status: Synced + syncPhase: Sync + version: v1beta1 + revision: c44295c14ed484dd4417f4f0ac0a0408aa1d33df + source: + path: vault-secrets-operator + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + reconciledAt: "2025-03-31T11:53:48Z" + resources: + - kind: ConfigMap + name: vault-secrets-operator-manager-config + namespace: vault-secrets-operator + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: vault-secrets-operator-metrics-service + namespace: vault-secrets-operator + status: Synced + version: v1 + - kind: ServiceAccount + name: vault-secrets-operator-controller-manager + namespace: vault-secrets-operator + status: Synced + version: v1 + - group: apiextensions.k8s.io + kind: CustomResourceDefinition + name: hcpauths.secrets.hashicorp.com + status: Synced + version: v1 + - group: apiextensions.k8s.io + kind: CustomResourceDefinition + name: hcpvaultsecretsapps.secrets.hashicorp.com + status: Synced + version: v1 + - group: apiextensions.k8s.io + kind: CustomResourceDefinition + name: secrettransformations.secrets.hashicorp.com + status: Synced + version: v1 + - group: apiextensions.k8s.io + kind: CustomResourceDefinition + name: vaultauthglobals.secrets.hashicorp.com + status: Synced + version: v1 + - group: apiextensions.k8s.io + kind: CustomResourceDefinition + name: vaultauths.secrets.hashicorp.com + status: Synced + version: v1 + - group: apiextensions.k8s.io + kind: CustomResourceDefinition + name: vaultconnections.secrets.hashicorp.com + status: Synced + version: v1 + - group: apiextensions.k8s.io + kind: CustomResourceDefinition + name: vaultdynamicsecrets.secrets.hashicorp.com + status: Synced + version: v1 + - group: apiextensions.k8s.io + kind: CustomResourceDefinition + name: vaultpkisecrets.secrets.hashicorp.com + status: Synced + version: v1 + - group: apiextensions.k8s.io + kind: CustomResourceDefinition + name: vaultstaticsecrets.secrets.hashicorp.com + status: Synced + version: v1 + - group: apps + health: + status: Healthy + kind: Deployment + name: vault-secrets-operator-controller-manager + namespace: vault-secrets-operator + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-hcpauth-editor-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-hcpauth-viewer-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-hcpsecretsapp-editor-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-hcpsecretsapp-viewer-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-manager-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-metrics-reader + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-proxy-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-secrettransformation-editor-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-secrettransformation-viewer-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-vaultauth-editor-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-vaultauth-viewer-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-vaultauthglobal-editor-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-vaultauthglobal-viewer-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-vaultconnection-editor-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-vaultconnection-viewer-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-vaultdynamicsecret-editor-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-vaultdynamicsecret-viewer-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-vaultpki-editor-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-vaultpki-viewer-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-vaultstaticsecret-editor-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-secrets-operator-vaultstaticsecret-viewer-role + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRoleBinding + name: vault-secrets-operator-manager-rolebinding + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRoleBinding + name: vault-secrets-operator-proxy-rolebinding + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: Role + name: vault-secrets-operator-leader-election-role + namespace: vault-secrets-operator + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: RoleBinding + name: vault-secrets-operator-leader-election-rolebinding + namespace: vault-secrets-operator + status: Synced + version: v1 + - group: secrets.hashicorp.com + kind: VaultAuth + name: vault-secrets-operator-default-transit-auth + namespace: vault-secrets-operator + status: Synced + version: v1beta1 + - group: secrets.hashicorp.com + kind: VaultConnection + name: default + namespace: vault-secrets-operator + status: Synced + version: v1beta1 + sourceType: Helm + summary: + images: + - hashicorp/vault-secrets-operator:0.10.0 + - quay.io/brancz/kube-rbac-proxy:v0.18.1 + sync: + comparedTo: + destination: + namespace: vault-secrets-operator + server: https://kubernetes.default.svc + source: + path: vault-secrets-operator + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + revision: c44295c14ed484dd4417f4f0ac0a0408aa1d33df + status: Synced diff --git a/argo-infra-apps/vault.yaml b/argo-infra-apps/vault.yaml new file mode 100644 index 0000000..c8e7eaa --- /dev/null +++ b/argo-infra-apps/vault.yaml @@ -0,0 +1,442 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"argoproj.io/v1alpha1","kind":"Application","metadata":{"annotations":{},"creationTimestamp":"2025-03-19T10:57:00Z","generation":1840,"labels":{"app.kubernetes.io/instance":"argo-infra-apps"},"name":"vault","namespace":"argocd","resourceVersion":"424507","uid":"62d1da68-9db5-4024-baa4-2f9bae7366f6"},"spec":{"destination":{"namespace":"vault","server":"https://kubernetes.default.svc"},"ignoreDifferences":[{"group":"admissionregistration.k8s.io","jsonPointers":["/webhooks/0/clientConfig/caBundle"],"kind":"MutatingWebhookConfiguration","name":"vault-agent-injector-cfg"}],"project":"default","source":{"helm":{"valueFiles":["values.yaml"]},"path":"vault","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"},"syncPolicy":{"automated":{"prune":true,"selfHeal":true},"syncOptions":["CreateNamespace=true"]}},"status":{"controllerNamespace":"argocd","health":{"status":"Healthy"},"history":[{"deployStartedAt":"2025-03-19T10:57:06Z","deployedAt":"2025-03-19T10:57:07Z","id":0,"initiatedBy":{"automated":true},"revision":"ea003db2768a9cadc1e8a6ca0c9f6368a165243a","source":{"helm":{"valueFiles":["values.yaml"]},"path":"vault","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}},{"deployStartedAt":"2025-03-19T11:32:51Z","deployedAt":"2025-03-19T11:32:52Z","id":1,"initiatedBy":{"username":"admin"},"revision":"ea003db2768a9cadc1e8a6ca0c9f6368a165243a","source":{"helm":{"valueFiles":["values.yaml"]},"path":"vault","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}}],"operationState":{"finishedAt":"2025-03-19T11:32:52Z","message":"successfully synced (all tasks run)","operation":{"initiatedBy":{"username":"admin"},"retry":{},"sync":{"revision":"ea003db2768a9cadc1e8a6ca0c9f6368a165243a","syncOptions":["CreateNamespace=true"],"syncStrategy":{"hook":{}}}},"phase":"Succeeded","startedAt":"2025-03-19T11:32:51Z","syncResult":{"resources":[{"group":"policy","hookPhase":"Running","kind":"PodDisruptionBudget","message":"poddisruptionbudget.policy/vault configured","name":"vault","namespace":"vault","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"ServiceAccount","message":"serviceaccount/vault-agent-injector unchanged","name":"vault-agent-injector","namespace":"vault","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"ServiceAccount","message":"serviceaccount/vault unchanged","name":"vault","namespace":"vault","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"ConfigMap","message":"configmap/vault-config unchanged","name":"vault-config","namespace":"vault","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"rbac.authorization.k8s.io","hookPhase":"Running","kind":"ClusterRole","message":"clusterrole.rbac.authorization.k8s.io/vault-agent-injector-clusterrole reconciled. clusterrole.rbac.authorization.k8s.io/vault-agent-injector-clusterrole unchanged","name":"vault-agent-injector-clusterrole","namespace":"vault","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"rbac.authorization.k8s.io","hookPhase":"Running","kind":"ClusterRoleBinding","message":"clusterrolebinding.rbac.authorization.k8s.io/vault-server-binding reconciled. clusterrolebinding.rbac.authorization.k8s.io/vault-server-binding unchanged","name":"vault-server-binding","namespace":"vault","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"rbac.authorization.k8s.io","hookPhase":"Running","kind":"ClusterRoleBinding","message":"clusterrolebinding.rbac.authorization.k8s.io/vault-agent-injector-binding reconciled. clusterrolebinding.rbac.authorization.k8s.io/vault-agent-injector-binding unchanged","name":"vault-agent-injector-binding","namespace":"vault","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"rbac.authorization.k8s.io","hookPhase":"Running","kind":"Role","message":"role.rbac.authorization.k8s.io/vault-discovery-role reconciled. role.rbac.authorization.k8s.io/vault-discovery-role unchanged","name":"vault-discovery-role","namespace":"vault","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"rbac.authorization.k8s.io","hookPhase":"Running","kind":"RoleBinding","message":"rolebinding.rbac.authorization.k8s.io/vault-discovery-rolebinding reconciled. rolebinding.rbac.authorization.k8s.io/vault-discovery-rolebinding unchanged","name":"vault-discovery-rolebinding","namespace":"vault","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"Service","message":"service/vault-standby unchanged","name":"vault-standby","namespace":"vault","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"Service","message":"service/vault-active unchanged","name":"vault-active","namespace":"vault","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"Service","message":"service/vault-internal unchanged","name":"vault-internal","namespace":"vault","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"Service","message":"service/vault-agent-injector-svc unchanged","name":"vault-agent-injector-svc","namespace":"vault","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"","hookPhase":"Running","kind":"Service","message":"service/vault unchanged","name":"vault","namespace":"vault","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"apps","hookPhase":"Running","kind":"Deployment","message":"deployment.apps/vault-agent-injector configured","name":"vault-agent-injector","namespace":"vault","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"apps","hookPhase":"Running","kind":"StatefulSet","message":"statefulset.apps/vault configured","name":"vault","namespace":"vault","status":"Synced","syncPhase":"Sync","version":"v1"},{"group":"admissionregistration.k8s.io","hookPhase":"Running","kind":"MutatingWebhookConfiguration","message":"mutatingwebhookconfiguration.admissionregistration.k8s.io/vault-agent-injector-cfg configured","name":"vault-agent-injector-cfg","namespace":"vault","status":"Synced","syncPhase":"Sync","version":"v1"}],"revision":"ea003db2768a9cadc1e8a6ca0c9f6368a165243a","source":{"helm":{"valueFiles":["values.yaml"]},"path":"vault","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}}},"reconciledAt":"2025-03-19T13:55:34Z","resources":[{"kind":"ConfigMap","name":"vault-config","namespace":"vault","status":"Synced","version":"v1"},{"health":{"status":"Healthy"},"kind":"Service","name":"vault","namespace":"vault","status":"Synced","version":"v1"},{"health":{"status":"Healthy"},"kind":"Service","name":"vault-active","namespace":"vault","status":"Synced","version":"v1"},{"health":{"status":"Healthy"},"kind":"Service","name":"vault-agent-injector-svc","namespace":"vault","status":"Synced","version":"v1"},{"health":{"status":"Healthy"},"kind":"Service","name":"vault-internal","namespace":"vault","status":"Synced","version":"v1"},{"health":{"status":"Healthy"},"kind":"Service","name":"vault-standby","namespace":"vault","status":"Synced","version":"v1"},{"kind":"ServiceAccount","name":"vault","namespace":"vault","status":"Synced","version":"v1"},{"kind":"ServiceAccount","name":"vault-agent-injector","namespace":"vault","status":"Synced","version":"v1"},{"group":"admissionregistration.k8s.io","kind":"MutatingWebhookConfiguration","name":"vault-agent-injector-cfg","status":"Synced","version":"v1"},{"group":"apps","health":{"status":"Healthy"},"kind":"Deployment","name":"vault-agent-injector","namespace":"vault","status":"Synced","version":"v1"},{"group":"apps","health":{"message":"statefulset has 3 ready pods","status":"Healthy"},"kind":"StatefulSet","name":"vault","namespace":"vault","status":"Synced","version":"v1"},{"group":"policy","kind":"PodDisruptionBudget","name":"vault","namespace":"vault","status":"Synced","version":"v1"},{"group":"rbac.authorization.k8s.io","kind":"ClusterRole","name":"vault-agent-injector-clusterrole","status":"Synced","version":"v1"},{"group":"rbac.authorization.k8s.io","kind":"ClusterRoleBinding","name":"vault-agent-injector-binding","status":"Synced","version":"v1"},{"group":"rbac.authorization.k8s.io","kind":"ClusterRoleBinding","name":"vault-server-binding","status":"Synced","version":"v1"},{"group":"rbac.authorization.k8s.io","kind":"Role","name":"vault-discovery-role","namespace":"vault","status":"Synced","version":"v1"},{"group":"rbac.authorization.k8s.io","kind":"RoleBinding","name":"vault-discovery-rolebinding","namespace":"vault","status":"Synced","version":"v1"}],"sourceType":"Helm","summary":{"images":["hashicorp/vault-k8s:1.6.2","hashicorp/vault:1.19.0"]},"sync":{"comparedTo":{"destination":{"namespace":"vault","server":"https://kubernetes.default.svc"},"ignoreDifferences":[{"group":"admissionregistration.k8s.io","jsonPointers":["/webhooks/0/clientConfig/caBundle"],"kind":"MutatingWebhookConfiguration","name":"vault-agent-injector-cfg"}],"source":{"helm":{"valueFiles":["values.yaml"]},"path":"vault","repoURL":"https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git","targetRevision":"main"}},"revision":"ea003db2768a9cadc1e8a6ca0c9f6368a165243a","status":"Synced"}}} + creationTimestamp: "2025-03-19T14:00:58Z" + generation: 76 + labels: + app.kubernetes.io/instance: argo-infra-apps + name: vault + namespace: argocd + resourceVersion: "441729" + uid: 495b57f6-384a-4a4e-b976-514011af6c45 +spec: + destination: + namespace: vault + server: https://kubernetes.default.svc + ignoreDifferences: + - group: admissionregistration.k8s.io + jsonPointers: + - /webhooks/0/clientConfig/caBundle + kind: MutatingWebhookConfiguration + name: vault-agent-injector-cfg + project: default + source: + helm: + valueFiles: + - values.yaml + path: vault + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true +status: + controllerNamespace: argocd + health: + status: Healthy + history: + - deployStartedAt: "2025-03-19T10:57:06Z" + deployedAt: "2025-03-19T10:57:07Z" + id: 0 + initiatedBy: + automated: true + revision: ea003db2768a9cadc1e8a6ca0c9f6368a165243a + source: + helm: + valueFiles: + - values.yaml + path: vault + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-03-19T11:32:51Z" + deployedAt: "2025-03-19T11:32:52Z" + id: 1 + initiatedBy: + username: admin + revision: ea003db2768a9cadc1e8a6ca0c9f6368a165243a + source: + helm: + valueFiles: + - values.yaml + path: vault + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-03-19T14:01:01Z" + deployedAt: "2025-03-19T14:01:04Z" + id: 2 + initiatedBy: + automated: true + revision: ccbcd028530e5528739ce1fd9d30fa1a835db178 + source: + helm: + valueFiles: + - values.yaml + path: vault + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + - deployStartedAt: "2025-03-19T14:11:37Z" + deployedAt: "2025-03-19T14:11:40Z" + id: 3 + initiatedBy: + username: admin + revision: 170f1d93a41905281cbf22e6e4bd394d1fd57b7f + source: + helm: + valueFiles: + - values.yaml + path: vault + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + operationState: + finishedAt: "2025-03-19T14:11:40Z" + message: successfully synced (all tasks run) + operation: + initiatedBy: + username: admin + retry: {} + sync: + prune: true + revision: 170f1d93a41905281cbf22e6e4bd394d1fd57b7f + syncOptions: + - CreateNamespace=true + - Replace=true + syncStrategy: + hook: + force: true + phase: Succeeded + startedAt: "2025-03-19T14:11:37Z" + syncResult: + resources: + - group: policy + hookPhase: Running + kind: PodDisruptionBudget + message: |- + poddisruptionbudget.policy "vault" deleted + poddisruptionbudget.policy/vault replaced + name: vault + namespace: vault + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: ServiceAccount + message: |- + serviceaccount "vault-agent-injector" deleted + serviceaccount/vault-agent-injector replaced + name: vault-agent-injector + namespace: vault + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: ServiceAccount + message: |- + serviceaccount "vault" deleted + serviceaccount/vault replaced + name: vault + namespace: vault + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: ConfigMap + message: |- + configmap "vault-config" deleted + configmap/vault-config replaced + name: vault-config + namespace: vault + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRole + message: |- + clusterrole.rbac.authorization.k8s.io/vault-agent-injector-clusterrole reconciled. clusterrole.rbac.authorization.k8s.io "vault-agent-injector-clusterrole" deleted + clusterrole.rbac.authorization.k8s.io/vault-agent-injector-clusterrole replaced + name: vault-agent-injector-clusterrole + namespace: vault + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRoleBinding + message: |- + clusterrolebinding.rbac.authorization.k8s.io/vault-server-binding reconciled. clusterrolebinding.rbac.authorization.k8s.io "vault-server-binding" deleted + clusterrolebinding.rbac.authorization.k8s.io/vault-server-binding replaced + name: vault-server-binding + namespace: vault + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: ClusterRoleBinding + message: |- + clusterrolebinding.rbac.authorization.k8s.io/vault-agent-injector-binding reconciled. clusterrolebinding.rbac.authorization.k8s.io "vault-agent-injector-binding" deleted + clusterrolebinding.rbac.authorization.k8s.io/vault-agent-injector-binding replaced + name: vault-agent-injector-binding + namespace: vault + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: Role + message: |- + role.rbac.authorization.k8s.io/vault-discovery-role reconciled. role.rbac.authorization.k8s.io "vault-discovery-role" deleted + role.rbac.authorization.k8s.io/vault-discovery-role replaced + name: vault-discovery-role + namespace: vault + status: Synced + syncPhase: Sync + version: v1 + - group: rbac.authorization.k8s.io + hookPhase: Running + kind: RoleBinding + message: |- + rolebinding.rbac.authorization.k8s.io/vault-discovery-rolebinding reconciled. rolebinding.rbac.authorization.k8s.io "vault-discovery-rolebinding" deleted + rolebinding.rbac.authorization.k8s.io/vault-discovery-rolebinding replaced + name: vault-discovery-rolebinding + namespace: vault + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: |- + service "vault-internal" deleted + service/vault-internal replaced + name: vault-internal + namespace: vault + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: |- + service "vault-agent-injector-svc" deleted + service/vault-agent-injector-svc replaced + name: vault-agent-injector-svc + namespace: vault + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: |- + service "vault-standby" deleted + service/vault-standby replaced + name: vault-standby + namespace: vault + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: |- + service "vault" deleted + service/vault replaced + name: vault + namespace: vault + status: Synced + syncPhase: Sync + version: v1 + - group: "" + hookPhase: Running + kind: Service + message: |- + service "vault-active" deleted + service/vault-active replaced + name: vault-active + namespace: vault + status: Synced + syncPhase: Sync + version: v1 + - group: apps + hookPhase: Running + kind: Deployment + message: |- + deployment.apps "vault-agent-injector" deleted + deployment.apps/vault-agent-injector replaced + name: vault-agent-injector + namespace: vault + status: Synced + syncPhase: Sync + version: v1 + - group: apps + hookPhase: Running + kind: StatefulSet + message: |- + statefulset.apps "vault" deleted + statefulset.apps/vault replaced + name: vault + namespace: vault + status: Synced + syncPhase: Sync + version: v1 + - group: admissionregistration.k8s.io + hookPhase: Running + kind: MutatingWebhookConfiguration + message: |- + mutatingwebhookconfiguration.admissionregistration.k8s.io "vault-agent-injector-cfg" deleted + mutatingwebhookconfiguration.admissionregistration.k8s.io/vault-agent-injector-cfg replaced + name: vault-agent-injector-cfg + namespace: vault + status: Synced + syncPhase: Sync + version: v1 + revision: 170f1d93a41905281cbf22e6e4bd394d1fd57b7f + source: + helm: + valueFiles: + - values.yaml + path: vault + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + reconciledAt: "2025-03-19T15:31:34Z" + resources: + - kind: ConfigMap + name: vault-config + namespace: vault + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: vault + namespace: vault + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: vault-active + namespace: vault + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: vault-agent-injector-svc + namespace: vault + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: vault-internal + namespace: vault + status: Synced + version: v1 + - health: + status: Healthy + kind: Service + name: vault-standby + namespace: vault + status: Synced + version: v1 + - kind: ServiceAccount + name: vault + namespace: vault + status: Synced + version: v1 + - kind: ServiceAccount + name: vault-agent-injector + namespace: vault + status: Synced + version: v1 + - group: admissionregistration.k8s.io + kind: MutatingWebhookConfiguration + name: vault-agent-injector-cfg + status: Synced + version: v1 + - group: apps + health: + status: Healthy + kind: Deployment + name: vault-agent-injector + namespace: vault + status: Synced + version: v1 + - group: apps + health: + message: statefulset has 3 ready pods + status: Healthy + kind: StatefulSet + name: vault + namespace: vault + status: Synced + version: v1 + - group: policy + kind: PodDisruptionBudget + name: vault + namespace: vault + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRole + name: vault-agent-injector-clusterrole + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRoleBinding + name: vault-agent-injector-binding + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: ClusterRoleBinding + name: vault-server-binding + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: Role + name: vault-discovery-role + namespace: vault + status: Synced + version: v1 + - group: rbac.authorization.k8s.io + kind: RoleBinding + name: vault-discovery-rolebinding + namespace: vault + status: Synced + version: v1 + sourceType: Helm + summary: + images: + - hashicorp/vault-k8s:1.6.2 + - hashicorp/vault:1.19.0 + sync: + comparedTo: + destination: + namespace: vault + server: https://kubernetes.default.svc + ignoreDifferences: + - group: admissionregistration.k8s.io + jsonPointers: + - /webhooks/0/clientConfig/caBundle + kind: MutatingWebhookConfiguration + name: vault-agent-injector-cfg + source: + helm: + valueFiles: + - values.yaml + path: vault + repoURL: https://gitlab.ii-p001.local/cw-devops/cw-infra-apps.git + targetRevision: main + revision: 51a8196fc681a3e098bb86eb1f2dd0889bfab910 + status: Synced diff --git a/caddy/.helmignore b/caddy/.helmignore new file mode 100644 index 0000000..b3123b9 --- /dev/null +++ b/caddy/.helmignore @@ -0,0 +1,26 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ + +ci/ +README.md.gotmpl diff --git a/caddy/Chart.yaml b/caddy/Chart.yaml new file mode 100644 index 0000000..88fc422 --- /dev/null +++ b/caddy/Chart.yaml @@ -0,0 +1,29 @@ +annotations: + artifacthub.io/changes: | + - kind: changed + description: Bump application to 2.4.5 + artifacthub.io/images: | + - name: caddy + image: caddy:2.4.5 +apiVersion: v2 +appVersion: 2.4.5 +description: A powerful, enterprise-ready, open source web server with automatic HTTPS + written in Go. +home: https://caddyserver.com/ +icon: https://caddyserver.com/resources/images/favicon.png +keywords: +- http +- https +- web +- server +kubeVersion: '>=1.16.0-0' +maintainers: +- email: mark.sagikazar@gmail.com + name: sagikazarmark + url: https://sagikazarmark.hu +name: caddy +sources: +- https://github.com/caddyserver/caddy +- https://github.com/sagikazarmark/helm-charts/tree/master/charts/caddy +type: application +version: 0.0.14 diff --git a/caddy/LICENSE b/caddy/LICENSE new file mode 100644 index 0000000..b27fd7e --- /dev/null +++ b/caddy/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2021 Márk Sági-Kazár + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/caddy/README.md b/caddy/README.md new file mode 100644 index 0000000..5e75d72 --- /dev/null +++ b/caddy/README.md @@ -0,0 +1,64 @@ +# caddy + +![version: 0.0.14](https://img.shields.io/badge/version-0.0.14-informational?style=flat-square) ![type: application](https://img.shields.io/badge/type-application-informational?style=flat-square) ![app version: 2.4.5](https://img.shields.io/badge/app%20version-2.4.5-informational?style=flat-square) ![kube version: >=1.16.0-0](https://img.shields.io/badge/kube%20version->=1.16.0--0-informational?style=flat-square) [![artifact hub](https://img.shields.io/badge/artifact%20hub-caddy-informational?style=flat-square)](https://artifacthub.io/packages/helm/sagikazarmark/caddy) + +A powerful, enterprise-ready, open source web server with automatic HTTPS written in Go. + +**Homepage:** + +## TL;DR; + +```bash +helm repo add skm https://charts.sagikazarmark.dev +helm install --generate-name --wait skm/caddy +``` + +## Limitations + +The chart currently only works with a `Caddyfile` that exposes content over port 80. + +HTTPS service support, metrics and a lot of other features are coming in later versions. + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| replicaCount | int | `1` | Number of replicas (pods) to launch. | +| image.repository | string | `"caddy"` | Name of the image repository to pull the container image from. | +| image.pullPolicy | string | `"IfNotPresent"` | [Image pull policy](https://kubernetes.io/docs/concepts/containers/images/#updating-images) for updating already existing images on a node. | +| image.tag | string | `""` | Image tag override for the default value (chart appVersion). | +| imagePullSecrets | list | `[]` | Reference to one or more secrets to be used when [pulling images](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/#create-a-pod-that-uses-your-secret) (from private registries). | +| nameOverride | string | `""` | A name in place of the chart name for `app:` labels. | +| fullnameOverride | string | `""` | A name to substitute for the full names of resources. | +| config | string | `nil` | Caddy configuration file content. Accepts [Caddyfile](https://caddyserver.com/docs/caddyfile) format by default. See `adapter` for other formats. | +| adapter | string | `"caddyfile"` | Caddyfile [config adapter](https://caddyserver.com/docs/config-adapters). Set it to empty string to use JSON. | +| watch | bool | `false` | Watch config file for changes and reload it automatically. | +| volumes | list | `[]` | Additional storage [volumes](https://kubernetes.io/docs/concepts/storage/volumes/). See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#volumes-1) for details. | +| volumeMounts | list | `[]` | Additional [volume mounts](https://kubernetes.io/docs/tasks/configure-pod-container/configure-volume-storage/). See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#volumes-1) for details. | +| envFrom | list | `[]` | Additional environment variables mounted from [secrets](https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets-as-environment-variables) or [config maps](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#configure-all-key-value-pairs-in-a-configmap-as-container-environment-variables). See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#environment-variables) for details. | +| env | object | `{}` | Additional environment variables passed directly to containers. See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#environment-variables) for details. | +| serviceAccount.create | bool | `true` | Enable service account creation. | +| serviceAccount.annotations | object | `{}` | Annotations to be added to the service account. | +| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template. | +| podAnnotations | object | `{}` | Annotations to be added to pods. | +| podSecurityContext | object | `{}` | Pod [security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod). See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#security-context) for details. | +| securityContext | object | `{}` | Container [security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container). See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#security-context-1) for details. | +| service.annotations | object | `{}` | Annotations to be added to the service. | +| service.type | string | `"ClusterIP"` | Kubernetes [service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types). | +| service.loadBalancerIP | string | `nil` | Only applies when the service type is LoadBalancer. Load balancer will get created with the IP specified in this field. | +| service.loadBalancerSourceRanges | list | `[]` | (list) If specified (and supported by the cloud provider), traffic through the load balancer will be restricted to the specified client IPs. Valid values are IP CIDR blocks. | +| service.port | int | `80` | Service port. | +| service.nodePort | int | `nil` | Service node port (when applicable). | +| service.externalTrafficPolicy | string | `nil` | Route external traffic to node-local or cluster-wide endoints. Useful for [preserving the client source IP](https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip). | +| ingress.enabled | bool | `false` | Enable [ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/). | +| ingress.className | string | `""` | Ingress [class name](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class). | +| ingress.annotations | object | `{}` | Annotations to be added to the ingress. | +| ingress.hosts | list | See [values.yaml](values.yaml). | Ingress host configuration. | +| ingress.tls | list | See [values.yaml](values.yaml). | Ingress TLS configuration. | +| resources | object | No requests or limits. | Container resource [requests and limits](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/). See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#resources) for details. | +| autoscaling | object | Disabled by default. | Autoscaling configuration (see [values.yaml](values.yaml) for details). | +| nodeSelector | object | `{}` | [Node selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) configuration. | +| tolerations | list | `[]` | [Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) for node taints. See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling) for details. | +| affinity | object | `{}` | [Affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) configuration. See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling) for details. | +| livenessProbe | object | `{"httpGet":{"path":"/","port":"http"}}` | [Liveness probe](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes) See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#Probe) for details. | +| readinessProbe | object | `{"httpGet":{"path":"/","port":"http"}}` | [Readiness probe](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes) See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#Probe) for details. | diff --git a/caddy/templates/NOTES.txt b/caddy/templates/NOTES.txt new file mode 100644 index 0000000..2f81c40 --- /dev/null +++ b/caddy/templates/NOTES.txt @@ -0,0 +1,22 @@ +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 "caddy.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 "caddy.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "caddy.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 "caddy.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/caddy/templates/_helpers.tpl b/caddy/templates/_helpers.tpl new file mode 100644 index 0000000..b42bfa2 --- /dev/null +++ b/caddy/templates/_helpers.tpl @@ -0,0 +1,75 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "caddy.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 "caddy.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 "caddy.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "caddy.labels" -}} +helm.sh/chart: {{ include "caddy.chart" . }} +{{ include "caddy.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "caddy.selectorLabels" -}} +app.kubernetes.io/name: {{ include "caddy.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "caddy.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "caddy.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Determine the configuration file name based on the adapter. +*/}} +{{- define "caddy.configFileName" -}} +{{- if or (not .Values.config) (eq .Values.adapter "caddyfile") }} +{{- print "Caddyfile" }} +{{- else if .Values.adapter }} +{{- printf "config.%s" .Values.adapter }} +{{- else }} +{{- print "config.json" }} +{{- end }} +{{- end }} diff --git a/caddy/templates/configmap.yaml b/caddy/templates/configmap.yaml new file mode 100644 index 0000000..650b1b4 --- /dev/null +++ b/caddy/templates/configmap.yaml @@ -0,0 +1,11 @@ +{{- if .Values.config -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "caddy.fullname" . }} + labels: + {{- include "caddy.labels" . | nindent 4 }} +data: + {{ include "caddy.configFileName" . }}: |- + {{- .Values.config | nindent 4 }} +{{- end }} diff --git a/caddy/templates/deployment.yaml b/caddy/templates/deployment.yaml new file mode 100644 index 0000000..170c93d --- /dev/null +++ b/caddy/templates/deployment.yaml @@ -0,0 +1,105 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "caddy.fullname" . }} + labels: + {{- include "caddy.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "caddy.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + {{- if not .Values.watch }} + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- end }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "caddy.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "caddy.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: + - caddy + - run + - --config + - /etc/caddy/{{ include "caddy.configFileName" . }} + {{- if and .Values.config .Values.adapter }} + - --adapter + - {{ .Values.adapter }} + {{- end }} + {{- if .Values.watch }} + - --watch + {{- end }} + {{- with .Values.env }} + env: + {{- range $key, $value := . }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- with .Values.envFrom }} + envFrom: + {{- toYaml . | nindent 12 }} + {{- end }} + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- if or .Values.config .Values.volumeMounts }} + volumeMounts: + {{- if .Values.config }} + - name: config + mountPath: /etc/caddy + readOnly: true + {{- end }} + {{- with .Values.volumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} + {{- if or .Values.config .Values.volumes }} + volumes: + {{- if .Values.config }} + - name: config + configMap: + name: {{ include "caddy.fullname" . }} + {{- end }} + {{- with .Values.volumes }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/caddy/templates/hpa.yaml b/caddy/templates/hpa.yaml new file mode 100644 index 0000000..b53edaa --- /dev/null +++ b/caddy/templates/hpa.yaml @@ -0,0 +1,28 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "caddy.fullname" . }} + labels: + {{- include "caddy.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "caddy.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/caddy/templates/ingress.yaml b/caddy/templates/ingress.yaml new file mode 100644 index 0000000..a919a2c --- /dev/null +++ b/caddy/templates/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "caddy.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "caddy.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/caddy/templates/service.yaml b/caddy/templates/service.yaml new file mode 100644 index 0000000..72e0f82 --- /dev/null +++ b/caddy/templates/service.yaml @@ -0,0 +1,36 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "caddy.fullname" . }} + labels: + {{- include "caddy.labels" . | nindent 4 }} + {{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + {{- with .Values.service.externalTrafficPolicy }} + externalTrafficPolicy: {{ . }} + {{- end }} + {{- if eq .Values.service.type "LoadBalancer" }} + {{- with .Values.service.loadBalancerIP }} + loadBalancerIP: {{ . }} + {{- end }} + {{- with .Values.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: {{ toYaml . | nindent 4 }} + {{- end }} + {{- end }} + ports: + - name: http + port: {{ .Values.service.port }} + {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) .Values.service.nodePort }} + nodePort: {{ .Values.service.nodePort }} + {{- end }} + targetPort: http + protocol: TCP + {{- if semverCompare ">=1.20-0" .Capabilities.KubeVersion.GitVersion }} + appProtocol: http + {{- end }} + selector: + {{- include "caddy.selectorLabels" . | nindent 4 }} diff --git a/caddy/templates/serviceaccount.yaml b/caddy/templates/serviceaccount.yaml new file mode 100644 index 0000000..94e0bf9 --- /dev/null +++ b/caddy/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "caddy.serviceAccountName" . }} + labels: + {{- include "caddy.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/caddy/templates/tests/test-connection.yaml b/caddy/templates/tests/test-connection.yaml new file mode 100644 index 0000000..047394a --- /dev/null +++ b/caddy/templates/tests/test-connection.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "caddy.fullname" . }}-test-connection" + labels: + {{- include "caddy.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: + - /bin/sh + - -c + - | + sleep 10 # Readiness takes some time + wget {{ include "caddy.fullname" . }}:{{ .Values.service.port }} + restartPolicy: Never diff --git a/caddy/values.yaml b/caddy/values.yaml new file mode 100644 index 0000000..cdbd1c5 --- /dev/null +++ b/caddy/values.yaml @@ -0,0 +1,180 @@ +# Default values for caddy. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# -- Number of replicas (pods) to launch. +replicaCount: 1 + +image: + # -- Name of the image repository to pull the container image from. + repository: caddyl4 + + # -- [Image pull policy](https://kubernetes.io/docs/concepts/containers/images/#updating-images) for updating already existing images on a node. + pullPolicy: IfNotPresent + + # -- Image tag override for the default value (chart appVersion). + tag: "" + +# -- Reference to one or more secrets to be used when [pulling images](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/#create-a-pod-that-uses-your-secret) (from private registries). +imagePullSecrets: [] + +# -- A name in place of the chart name for `app:` labels. +nameOverride: "" + +# -- A name to substitute for the full names of resources. +fullnameOverride: "" + +# -- (string) Caddy configuration file content. Accepts [Caddyfile](https://caddyserver.com/docs/caddyfile) format by default. +# See `adapter` for other formats. +config: + +# -- Caddyfile [config adapter](https://caddyserver.com/docs/config-adapters). Set it to empty string to use JSON. +adapter: caddyfile + +# -- Watch config file for changes and reload it automatically. +watch: false + +# -- Additional storage [volumes](https://kubernetes.io/docs/concepts/storage/volumes/). +# See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#volumes-1) for details. +volumes: [] + +# -- Additional [volume mounts](https://kubernetes.io/docs/tasks/configure-pod-container/configure-volume-storage/). +# See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#volumes-1) for details. +volumeMounts: [] + +# -- Additional environment variables mounted from [secrets](https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets-as-environment-variables) or [config maps](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#configure-all-key-value-pairs-in-a-configmap-as-container-environment-variables). +# See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#environment-variables) for details. +envFrom: [] + +# -- Additional environment variables passed directly to containers. +# See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#environment-variables) for details. +env: {} + +serviceAccount: + # -- Enable service account creation. + create: true + + # -- Annotations to be added 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: "" + +# -- Annotations to be added to pods. +podAnnotations: {} + +# -- Pod [security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod). +# See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#security-context) for details. +podSecurityContext: {} + # fsGroup: 2000 + +# -- Container [security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container). +# See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#security-context-1) for details. +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + # -- Annotations to be added to the service. + annotations: {} + + # -- Kubernetes [service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types). + type: ClusterIP + + # -- (string) Only applies when the service type is LoadBalancer. Load balancer will get created with the IP specified in this field. + loadBalancerIP: + + # -- (list) If specified (and supported by the cloud provider), traffic through the load balancer will be restricted to the specified client IPs. + # Valid values are IP CIDR blocks. + loadBalancerSourceRanges: [] + + # -- Service port. + port: 80 + + # -- (int) Service node port (when applicable). + nodePort: + + # -- Route external traffic to node-local or cluster-wide endoints. + # Useful for [preserving the client source IP](https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip). + externalTrafficPolicy: + +ingress: + # -- Enable [ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/). + enabled: false + + # -- Ingress [class name](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class). + className: "" + + # -- Annotations to be added to the ingress. + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + + # -- Ingress host configuration. + # @default -- See [values.yaml](values.yaml). + hosts: + - host: chart-example.local + paths: + - path: / + pathType: ImplementationSpecific + + # -- Ingress TLS configuration. + # @default -- See [values.yaml](values.yaml). + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +# -- Container resource [requests and limits](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/). +# See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#resources) for details. +# @default -- No requests or limits. +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 configuration (see [values.yaml](values.yaml) for details). +# @default -- Disabled by default. +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +# -- [Node selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) configuration. +nodeSelector: {} + +# -- [Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) for node taints. +# See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling) for details. +tolerations: [] + +# -- [Affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) configuration. +# See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling) for details. +affinity: {} + +# -- [Liveness probe](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes) +# See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#Probe) for details. +livenessProbe: + httpGet: + path: / + port: http + +# -- [Readiness probe](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes) +# See the [API reference](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#Probe) for details. +readinessProbe: + httpGet: + path: / + port: http diff --git a/cassandra/.helmignore b/cassandra/.helmignore new file mode 100644 index 0000000..207983f --- /dev/null +++ b/cassandra/.helmignore @@ -0,0 +1,25 @@ +# 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 +# img folder +img/ +# Changelog +CHANGELOG.md diff --git a/cassandra/Chart.lock b/cassandra/Chart.lock new file mode 100644 index 0000000..ea9df4f --- /dev/null +++ b/cassandra/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common + repository: oci://registry-1.docker.io/bitnamicharts + version: 2.30.0 +digest: sha256:46afdf79eae69065904d430f03f7e5b79a148afed20aa45ee83ba88adc036169 +generated: "2025-03-05T09:18:46.745709854Z" diff --git a/cassandra/Chart.yaml b/cassandra/Chart.yaml new file mode 100644 index 0000000..ca48e94 --- /dev/null +++ b/cassandra/Chart.yaml @@ -0,0 +1,34 @@ +annotations: + category: Database + images: | + - name: cassandra + image: docker.io/bitnami/cassandra:5.0.3-debian-12-r6 + - name: cassandra-exporter + image: docker.io/bitnami/cassandra-exporter:2.3.8-debian-12-r41 + - name: os-shell + image: docker.io/bitnami/os-shell:12-debian-12-r39 + licenses: Apache-2.0 +apiVersion: v2 +appVersion: 5.0.3 +dependencies: +- name: common + repository: oci://registry-1.docker.io/bitnamicharts + tags: + - bitnami-common + version: 2.x.x +description: Apache Cassandra is an open source distributed database management system + designed to handle large amounts of data across many servers, providing high availability + with no single point of failure. And lets test it. Now. +home: https://bitnami.com +icon: https://dyltqmyl993wv.cloudfront.net/assets/stacks/cassandra/img/cassandra-stack-220x234.png +keywords: +- cassandra +- database +- nosql +maintainers: +- name: Broadcom, Inc. All Rights Reserved. + url: https://github.com/bitnami/charts +name: cassandra +sources: +- https://github.com/bitnami/charts/tree/main/bitnami/cassandra +version: 12.2.1 diff --git a/cassandra/README.md b/cassandra/README.md new file mode 100644 index 0000000..77f6e20 --- /dev/null +++ b/cassandra/README.md @@ -0,0 +1,574 @@ + + +console.sql has a big size and must be used as init script for our database. Due to a huge size it can't be placed inside configmap, and must be compresseed + +gzip -c console.sql > init.cql.gz +after compression it must be placed in init_cm.yaml configmap as a binary data with +kubectl create configmap cassandra-init-script --from-file=init.cql.gz -n cassandra or in helm chart template + +https://gemspacepro.atlassian.net/wiki/spaces/GEMB2B/pages/224657714 files are here; + + + +# Bitnami package for Apache Cassandra + +Apache Cassandra is an open source distributed database management system designed to handle large amounts of data across many servers, providing high availability with no single point of failure. + +[Overview of Apache Cassandra](http://cassandra.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 install my-release oci://registry-1.docker.io/bitnamicharts/cassandra +``` + +Looking to use Apache Cassandra in production? Try [VMware Tanzu Application Catalog](https://bitnami.com/enterprise), the commercial edition of the Bitnami catalog. + +## Introduction + +This chart bootstraps an [Apache Cassandra](https://github.com/bitnami/containers/tree/main/bitnami/cassandra) 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.23+ +- Helm 3.8.0+ +- PV provisioner support in the underlying infrastructure + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```console +helm install my-release oci://REGISTRY_NAME/REPOSITORY_NAME/cassandra +``` + +> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. + +These commands deploy one node with Apache Cassandra 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` + +## Configuration and installation details + +### Resource requests and limits + +Bitnami charts allow setting resource requests and limits for all containers inside the chart deployment. These are inside the `resources` value (check parameter table). Setting requests is essential for production workloads and these should be adapted to your specific use case. + +To make this process easier, the chart contains the `resourcesPreset` values, which automatically sets the `resources` section according to different presets. Check these presets in [the bitnami/common chart](https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15). However, in production workloads using `resourcesPreset` is discouraged as it may not fully adapt to your specific needs. Find more information on container resource management in the [official Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/). + +### Update credentials + +Bitnami charts configure credentials at first boot. Any further change in the secrets or credentials require manual intervention. Follow these instructions: + +- Update the user password following [the upstream documentation](https://docs.datastax.com/en/cql-oss/3.x/cql/cql_reference/cqlAlterUser.html) +- Update the password secret with the new values (replace the SECRET_NAME and PASSWORD placeholders) + +```shell +kubectl create secret generic SECRET_NAME --from-literal=cassandra-password=PASSWORD --dry-run -o yaml | kubectl apply -f - +``` + +### [Rolling vs Immutable tags](https://techdocs.broadcom.com/us/en/vmware-tanzu/application-catalog/tanzu-application-catalog/services/tac-doc/apps-tutorials-understand-rolling-tags-containers-index.html) + +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. + +### Prometheus metrics + +This chart can be integrated with Prometheus by setting `metrics.enabled` to `true`. This will deploy a sidecar container with [cassandra_exporter](https://github.com/criteo/cassandra_exporter) in all pods and will expose it via the Cassandra service. This service will have the necessary annotations to be automatically scraped by Prometheus. + +#### Prometheus requirements + +It is necessary to have a working installation of Prometheus or Prometheus Operator for the integration to work. Install the [Bitnami Prometheus helm chart](https://github.com/bitnami/charts/tree/main/bitnami/prometheus) or the [Bitnami Kube Prometheus helm chart](https://github.com/bitnami/charts/tree/main/bitnami/kube-prometheus) to easily have a working Prometheus in your cluster. + +#### Integration with Prometheus Operator + +The chart can deploy `ServiceMonitor` objects for integration with Prometheus Operator installations. To do so, set the value `metrics.serviceMonitor.enabled=true`. Ensure that the Prometheus Operator `CustomResourceDefinitions` are installed in the cluster or it will fail with the following error: + +```text +no matches for kind "ServiceMonitor" in version "monitoring.coreos.com/v1" +``` + +Install the [Bitnami Kube Prometheus helm chart](https://github.com/bitnami/charts/tree/main/bitnami/kube-prometheus) for having the necessary CRDs and the Prometheus Operator. + +### Enable TLS + +This chart supports TLS between client and server and between nodes, as explained below: + +- For internode cluster encryption, set the `tls.internodeEncryption` chart parameter to a value different from `none`. Available values are `all`, `dc` or `rack`. +- For client-server encryption, set the `tls.clientEncryption` chart parameter to `true`. + +In both cases, it is also necessary to create a secret containing the keystore and truststore certificates and their corresponding protection passwords. This secret is to be passed to the chart via the `tls.existingSecret` parameter at deployment-time, as shown below: + +```text +tls.internodeEncryption=all +tls.clientEncryption=true +tls.existingSecret=my-exisiting-stores +tls.passwordsSecret=my-stores-password +``` + +> TIP: The secret may be created in the standard way with the `--from-file=./keystore`, `--from-file=./truststore`, `--from-literal=keystore-password=KEYSTORE_PASSWORD` and `--from-literal=truststore-password=TRUSTSTORE_PASSWORD` options. This assumes that the stores are in the current working directory and the KEYSTORE_PASSWORD and TRUSTSTORE_PASSWORD placeholders are replaced with the correct keystore and truststore passwords respectively. Example: + +```console +kubectl create secret generic my-exisiting-stores --from-file=./keystore --from-file=./truststore +kubectl create secret generic my-stores-password --from-literal=keystore-password=KEYSTORE_PASSWORD --from-literal=truststore-password=TRUSTSTORE_PASSWORD +``` + +Keystore and Truststore files can be dynamically created from the certificates files. In this case a secret with the tls.crt, tls.key and ca.crt in pem format is required. The following example shows how the secret can be created and assumes that all certificate files are in the working directory: + +```console +kubectl create secret tls my-certs --cert ./tls.crt --key ./tls.key +kubectl patch secret my-certs -p="{\"data\":{\"ca.crt\": \"$(cat ./ca.crt | base64 )\"}}" +``` + +To enable this feature `tls.autoGenerated` must be set and the new secret should be set in `tls.certificateSecret`: + +```text +tls.internodeEncryption=all +tls.clientEncryption=true +tls.autoGenerated=true +tls.certificatesSecret=my-certs +tls.passwordsSecret=my-stores-password +``` + +### Initialize the database + +The [Apache Cassandra](https://github.com/bitnami/containers/tree/main/bitnami/cassandra) image supports the use of custom scripts to initialize a fresh instance. This may be done by creating a Kubernetes ConfigMap that includes the necessary `.sh` or `.cql` scripts and passing this ConfigMap to the chart via the `initDBConfigMap` parameter. + +### Use a custom configuration file + +This chart also supports mounting custom configuration file(s) for Apache Cassandra. This is achieved by setting the `existingConfiguration` parameter with the name of a ConfigMap that includes the custom configuration file(s). Here is an example of deploying the chart with a custom configuration file stored in a ConfigMap named `cassandra-configuration`: + +```text +existingConfiguration=cassandra-configuration +``` + +> NOTE: This ConfigMap will override other Apache Cassandra configuration variables set in the chart. + +### Backup and restore + +Refer to our detailed tutorial on [backing up and restoring Bitnami Apache Cassandra deployments on Kubernetes](https://techdocs.broadcom.com/us/en/vmware-tanzu/application-catalog/tanzu-application-catalog/services/tac-doc/apps-tutorials-backup-restore-data-cassandra-kubernetes-index.html). + +### Set pod affinity + +This chart allows you to set custom pod 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. + +## Persistence + +The [Bitnami Apache Cassandra](https://github.com/bitnami/containers/tree/main/bitnami/cassandra) image stores the Apache Cassandra data at the `/bitnami/cassandra` 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. There are two approaches to achieve this: + +- Use Kubernetes SecurityContexts by setting the `podSecurityContext.enabled` and `containerSecurityContext.enabled` to `true`. This option is enabled by default in the chart. However, this feature does not work in all Kubernetes distributions. +- Use an init container to change the ownership of the volume before mounting it in the final destination. Enable this container by setting the `volumePermissions.enabled` parameter to `true`. + +## Parameters + +### Global parameters + +| Name | Description | Value | +| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| `global.imageRegistry` | Global Docker image registry | `""` | +| `global.imagePullSecrets` | Global Docker registry secret names as an array | `[]` | +| `global.defaultStorageClass` | Global default StorageClass for Persistent Volume(s) | `""` | +| `global.security.allowInsecureImages` | Allows skipping image verification | `false` | +| `global.compatibility.openshift.adaptSecurityContext` | Adapt the securityContext sections of the deployment to make them compatible with Openshift restricted-v2 SCC: remove runAsUser, runAsGroup and fsGroup and let the platform use their allowed default IDs. Possible values: auto (apply if the detected running cluster is Openshift), force (perform the adaptation always), disabled (do not perform adaptation) | `auto` | + +### Common parameters + +| Name | Description | Value | +| ------------------------ | --------------------------------------------------------------------------------------- | --------------- | +| `nameOverride` | String to partially override common.names.fullname | `""` | +| `fullnameOverride` | String to fully override common.names.fullname | `""` | +| `kubeVersion` | Force target Kubernetes version (using Helm capabilities if not set) | `""` | +| `commonLabels` | Labels to add to all deployed objects (sub-charts are not considered) | `{}` | +| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | +| `clusterDomain` | Kubernetes cluster domain name | `cluster.local` | +| `extraDeploy` | Array of extra objects to deploy with the release | `[]` | +| `usePasswordFiles` | Mount credentials as files instead of using environment variables | `true` | +| `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"]` | + +### Cassandra parameters + +| Name | Description | Value | +| -------------------------- | ---------------------------------------------------------------------------------------------------------------------- | --------------------------- | +| `image.registry` | Cassandra image registry | `REGISTRY_NAME` | +| `image.repository` | Cassandra image repository | `REPOSITORY_NAME/cassandra` | +| `image.digest` | Cassandra image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | +| `image.pullPolicy` | image pull policy | `IfNotPresent` | +| `image.pullSecrets` | Cassandra image pull secrets | `[]` | +| `image.debug` | Enable image debug mode | `false` | +| `dbUser.user` | Cassandra admin user | `cassandra` | +| `dbUser.forcePassword` | Force the user to provide a non | `false` | +| `dbUser.password` | Password for `dbUser.user`. Randomly generated if empty | `""` | +| `dbUser.existingSecret` | Use an existing secret object for `dbUser.user` password (will ignore `dbUser.password`) | `""` | +| `initDB` | Object with cql scripts. Useful for creating a keyspace and pre-populating data | `{}` | +| `initDBConfigMap` | ConfigMap with cql scripts. Useful for creating a keyspace and pre-populating data | `""` | +| `initDBSecret` | Secret with cql script (with sensitive data). Useful for creating a keyspace and pre-populating data | `""` | +| `existingConfiguration` | ConfigMap with custom cassandra configuration files. This overrides any other Cassandra configuration set in the chart | `""` | +| `cluster.name` | Cassandra cluster name | `cassandra` | +| `cluster.seedCount` | Number of seed nodes | `1` | +| `cluster.numTokens` | Number of tokens for each node | `256` | +| `cluster.datacenter` | Datacenter name | `dc1` | +| `cluster.rack` | Rack name | `rack1` | +| `cluster.endpointSnitch` | Endpoint Snitch | `SimpleSnitch` | +| `cluster.clientEncryption` | Client Encryption | `false` | +| `cluster.extraSeeds` | For an external/second cassandra ring. | `[]` | +| `cluster.enableUDF` | Enable User defined functions | `false` | +| `jvm.extraOpts` | Set the value for Java Virtual Machine extra options | `""` | +| `jvm.maxHeapSize` | Set Java Virtual Machine maximum heap size (MAX_HEAP_SIZE). Calculated automatically if `nil` | `""` | +| `jvm.newHeapSize` | Set Java Virtual Machine new heap size (HEAP_NEWSIZE). Calculated automatically if `nil` | `""` | +| `command` | Command for running the container (set to default if not set). Use array form | `[]` | +| `args` | Args for running the container (set to default if not set). Use array form | `[]` | +| `extraEnvVars` | Extra environment variables to be set on cassandra container | `[]` | +| `extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars | `""` | +| `extraEnvVarsSecret` | Name of existing Secret containing extra env vars | `""` | + +### Statefulset parameters + +| Name | Description | Value | +| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | +| `replicaCount` | Number of Cassandra replicas | `1` | +| `updateStrategy.type` | updateStrategy for Cassandra statefulset | `RollingUpdate` | +| `automountServiceAccountToken` | Mount Service Account token in pod | `false` | +| `hostAliases` | Add deployment host aliases | `[]` | +| `podManagementPolicy` | StatefulSet pod management policy | `OrderedReady` | +| `priorityClassName` | Cassandra pods' priority. | `""` | +| `podAnnotations` | Additional pod annotations | `{}` | +| `podLabels` | Additional pod labels | `{}` | +| `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 | `[]` | +| `podSecurityContext.enabled` | Enabled Cassandra pods' Security Context | `true` | +| `podSecurityContext.fsGroupChangePolicy` | Set filesystem group change policy | `Always` | +| `podSecurityContext.sysctls` | Set kernel settings using the sysctl interface | `[]` | +| `podSecurityContext.supplementalGroups` | Set filesystem extra groups | `[]` | +| `podSecurityContext.fsGroup` | Set Cassandra pod's Security Context fsGroup | `1001` | +| `containerSecurityContext.enabled` | Enabled Cassandra containers' Security Context | `true` | +| `containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | +| `containerSecurityContext.runAsUser` | Set Cassandra containers' Security Context runAsUser | `1001` | +| `containerSecurityContext.runAsGroup` | Set Cassandra containers' Security Context runAsGroup | `1001` | +| `containerSecurityContext.allowPrivilegeEscalation` | Set Cassandra containers' Security Context allowPrivilegeEscalation | `false` | +| `containerSecurityContext.capabilities.drop` | Set Cassandra containers' Security Context capabilities to be dropped | `["ALL"]` | +| `containerSecurityContext.readOnlyRootFilesystem` | Set Cassandra containers' Security Context readOnlyRootFilesystem | `true` | +| `containerSecurityContext.runAsNonRoot` | Set Cassandra containers' Security Context runAsNonRoot | `true` | +| `containerSecurityContext.privileged` | Set container's Security Context privileged | `false` | +| `containerSecurityContext.seccompProfile.type` | Set container's Security Context seccomp profile | `RuntimeDefault` | +| `resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if resources is set (resources is recommended for production). | `large` | +| `resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | +| `livenessProbe.enabled` | Enable livenessProbe | `true` | +| `livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `60` | +| `livenessProbe.periodSeconds` | Period seconds for livenessProbe | `30` | +| `livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `30` | +| `livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `5` | +| `livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | +| `readinessProbe.enabled` | Enable readinessProbe | `true` | +| `readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `60` | +| `readinessProbe.periodSeconds` | Period seconds for readinessProbe | `10` | +| `readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `30` | +| `readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `5` | +| `readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | +| `startupProbe.enabled` | Enable startupProbe | `false` | +| `startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `0` | +| `startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | +| `startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `5` | +| `startupProbe.failureThreshold` | Failure threshold for startupProbe | `60` | +| `startupProbe.successThreshold` | Success threshold for startupProbe | `1` | +| `customLivenessProbe` | Custom livenessProbe that overrides the default one | `{}` | +| `customReadinessProbe` | Custom readinessProbe that overrides the default one | `{}` | +| `customStartupProbe` | Override default startup probe | `{}` | +| `lifecycleHooks` | Override default etcd container hooks | `{}` | +| `schedulerName` | Alternative scheduler | `""` | +| `terminationGracePeriodSeconds` | In seconds, time the given to the Cassandra pod needs to terminate gracefully | `""` | +| `extraVolumes` | Optionally specify extra list of additional volumes for cassandra container | `[]` | +| `extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for cassandra container | `[]` | +| `initContainers` | Add additional init containers to the cassandra pods | `[]` | +| `sidecars` | Add additional sidecar containers to the cassandra pods | `[]` | +| `pdb.create` | Enable/disable a Pod Disruption Budget creation | `true` | +| `pdb.minAvailable` | Mininimum number of pods that must still be available after the eviction | `""` | +| `pdb.maxUnavailable` | Max number of pods that can be unavailable after the eviction | `""` | +| `hostNetwork` | Enable HOST Network | `false` | +| `containerPorts.intra` | Intra Port on the Host and Container | `7000` | +| `containerPorts.tls` | TLS Port on the Host and Container | `7001` | +| `containerPorts.jmx` | JMX Port on the Host and Container | `7199` | +| `containerPorts.cql` | CQL Port on the Host and Container | `9042` | +| `hostPorts.intra` | Intra Port on the Host | `""` | +| `hostPorts.tls` | TLS Port on the Host | `""` | +| `hostPorts.jmx` | JMX Port on the Host | `""` | +| `hostPorts.cql` | CQL Port on the Host | `""` | + +### RBAC parameters + +| Name | Description | Value | +| --------------------------------------------- | ---------------------------------------------------------- | ------- | +| `serviceAccount.create` | Enable the creation of a ServiceAccount for Cassandra pods | `true` | +| `serviceAccount.name` | The name of the ServiceAccount to use. | `""` | +| `serviceAccount.annotations` | Annotations for Cassandra Service Account | `{}` | +| `serviceAccount.automountServiceAccountToken` | Automount API credentials for a service account. | `false` | + +### Traffic Exposure Parameters + +| Name | Description | Value | +| --------------------------------------- | ---------------------------------------------------------------------------------- | ----------- | +| `service.type` | Cassandra service type | `ClusterIP` | +| `service.ports.cql` | Cassandra service CQL Port | `9042` | +| `service.ports.metrics` | Cassandra service metrics port | `8080` | +| `service.nodePorts.cql` | Node port for CQL | `""` | +| `service.nodePorts.metrics` | Node port for metrics | `""` | +| `service.extraPorts` | Extra ports to expose in the service (normally used with the `sidecar` value) | `[]` | +| `service.loadBalancerIP` | LoadBalancerIP if service type is `LoadBalancer` | `""` | +| `service.loadBalancerSourceRanges` | Service Load Balancer sources | `[]` | +| `service.clusterIP` | Service Cluster IP | `""` | +| `service.externalTrafficPolicy` | Service external traffic policy | `Cluster` | +| `service.annotations` | Provide any additional annotations which may be required. | `{}` | +| `service.sessionAffinity` | Session Affinity for Kubernetes service, can be "None" or "ClientIP" | `None` | +| `service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | +| `service.headless.annotations` | Annotations for the headless service. | `{}` | +| `networkPolicy.enabled` | Specifies whether a NetworkPolicy should be created | `true` | +| `networkPolicy.allowExternal` | Don't require server label for connections | `true` | +| `networkPolicy.allowExternalEgress` | Allow the pod to access any range of port and all destinations. | `true` | +| `networkPolicy.extraIngress` | Add extra ingress rules to the NetworkPolicy | `[]` | +| `networkPolicy.extraEgress` | Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true) | `[]` | +| `networkPolicy.ingressNSMatchLabels` | Labels to match to allow traffic from other namespaces | `{}` | +| `networkPolicy.ingressNSPodMatchLabels` | Pod labels to match to allow traffic from other namespaces | `{}` | + +### Persistence parameters + +| Name | Description | Value | +| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | +| `persistence.enabled` | Enable Cassandra data persistence using PVC, use a Persistent Volume Claim, If false, use emptyDir | `true` | +| `persistence.existingClaim` | Name of an existing PVC to use | `""` | +| `persistence.storageClass` | PVC Storage Class for Cassandra data volume | `""` | +| `persistence.commitStorageClass` | PVC Storage Class for Cassandra Commit Log volume | `""` | +| `persistence.annotations` | Persistent Volume Claim annotations | `{}` | +| `persistence.accessModes` | Persistent Volume Access Mode | `["ReadWriteOnce"]` | +| `persistence.size` | PVC Storage Request for Cassandra data volume | `8Gi` | +| `persistence.commitLogsize` | PVC Storage Request for Cassandra commit log volume. Unset by default | `2Gi` | +| `persistence.mountPath` | The path the data volume will be mounted at | `/bitnami/cassandra` | +| `persistence.commitLogMountPath` | The path the commit log volume will be mounted at. Unset by default. Set it to '/bitnami/cassandra/commitlog' to enable a separate commit log volume | `""` | + +### 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 image registry | `REGISTRY_NAME` | +| `volumePermissions.image.repository` | Init container volume image repository | `REPOSITORY_NAME/os-shell` | +| `volumePermissions.image.digest` | Init container volume image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | +| `volumePermissions.image.pullPolicy` | Init container volume pull policy | `IfNotPresent` | +| `volumePermissions.image.pullSecrets` | Specify docker-registry secret names as an array | `[]` | +| `volumePermissions.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if volumePermissions.resources is set (volumePermissions.resources is recommended for production). | `nano` | +| `volumePermissions.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | +| `volumePermissions.securityContext.seLinuxOptions` | Set SELinux options in container | `{}` | +| `volumePermissions.securityContext.runAsUser` | User ID for the init container | `0` | + +### Metrics parameters + +| Name | Description | Value | +| -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | +| `metrics.enabled` | Start a side-car prometheus exporter | `false` | +| `metrics.image.registry` | Cassandra exporter image registry | `REGISTRY_NAME` | +| `metrics.image.repository` | Cassandra exporter image name | `REPOSITORY_NAME/cassandra-exporter` | +| `metrics.image.digest` | Cassandra exporter image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | +| `metrics.image.pullPolicy` | image pull policy | `IfNotPresent` | +| `metrics.image.pullSecrets` | Specify docker-registry secret names as an array | `[]` | +| `metrics.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if metrics.resources is set (metrics.resources is recommended for production). | `nano` | +| `metrics.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | +| `metrics.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `20` | +| `metrics.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `10` | +| `metrics.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `45` | +| `metrics.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `3` | +| `metrics.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | +| `metrics.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for cassandra-exporter container | `[]` | +| `metrics.podAnnotations` | Metrics exporter pod Annotation and Labels | `{}` | +| `metrics.serviceMonitor.enabled` | If `true`, creates a Prometheus Operator ServiceMonitor (also requires `metrics.enabled` to be `true`) | `false` | +| `metrics.serviceMonitor.namespace` | Namespace in which Prometheus is running | `monitoring` | +| `metrics.serviceMonitor.interval` | Interval at which metrics should be scraped. | `""` | +| `metrics.serviceMonitor.scrapeTimeout` | Timeout after which the scrape is ended | `""` | +| `metrics.serviceMonitor.selector` | Prometheus instance selector labels | `{}` | +| `metrics.serviceMonitor.metricRelabelings` | Specify Metric Relabelings to add to the scrape endpoint | `[]` | +| `metrics.serviceMonitor.relabelings` | RelabelConfigs to apply to samples before scraping | `[]` | +| `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.serviceMonitor.labels` | Used to pass Labels that are required by the installed Prometheus Operator | `{}` | +| `metrics.containerPorts.http` | HTTP Port on the Host and Container | `8080` | +| `metrics.containerPorts.jmx` | JMX Port on the Host and Container | `5555` | +| `metrics.hostPorts.http` | HTTP Port on the Host | `""` | +| `metrics.hostPorts.jmx` | JMX Port on the Host | `""` | +| `metrics.configuration` | Configure Cassandra-exporter with a custom config.yml file | `""` | + +### TLS/SSL parameters + +| Name | Description | Value | +| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| `tls.internodeEncryption` | Set internode encryption | `none` | +| `tls.clientEncryption` | Set client-server encryption | `false` | +| `tls.autoGenerated` | Generate automatically self-signed TLS certificates. Currently only supports PEM certificates | `false` | +| `tls.existingSecret` | Existing secret that contains Cassandra Keystore and truststore | `""` | +| `tls.passwordsSecret` | Secret containing the Keystore and Truststore passwords if needed | `""` | +| `tls.keystorePassword` | Password for the keystore, if needed. | `""` | +| `tls.truststorePassword` | Password for the truststore, if needed. | `""` | +| `tls.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if tls.resources is set (tls.resources is recommended for production). | `nano` | +| `tls.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | +| `tls.certificatesSecret` | Secret with the TLS certificates. | `""` | +| `tls.tlsEncryptionSecretName` | Secret with the encryption of the TLS certificates | `""` | + +The above parameters map to the env variables defined in [bitnami/cassandra](https://github.com/bitnami/containers/tree/main/bitnami/cassandra). For more information please refer to the [bitnami/cassandra](https://github.com/bitnami/containers/tree/main/bitnami/cassandra) image documentation. + +Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +helm install my-release \ + --set dbUser.user=admin,dbUser.password=password \ + oci://REGISTRY_NAME/REPOSITORY_NAME/cassandra +``` + +> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. + +Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example, + +```console +helm install my-release -f values.yaml oci://REGISTRY_NAME/REPOSITORY_NAME/cassandra +``` + +> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. +> **Tip**: You can use the default [values.yaml](https://github.com/bitnami/charts/tree/main/bitnami/cassandra/values.yaml) + +## 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 `dbUser.password` 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. Please note down the password and run the command below to upgrade your chart: + +```console +helm upgrade my-release oci://REGISTRY_NAME/REPOSITORY_NAME/cassandra --set dbUser.password=[PASSWORD] +``` + +> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. + +| Note: you need to substitute the placeholder *[PASSWORD]* with the value obtained in the installation notes. + +### To 12.1.0 + +This version introduces image verification for security purposes. To disable it, set `global.security.allowInsecureImages` to `true`. More details at [GitHub issue](https://github.com/bitnami/charts/issues/30850). + +### To 12.0.0 + +Cassandra's version was bumped to `5.0`, [the latest GA version](https://cassandra.apache.org/_/blog/Apache-Cassandra-5.0-Announcement.html). Users can upgrade from version 4 to 5.0 through an online upgrade, minimizing downtime for applications. Nevertheless, a backup creation prior to undergoing the upgrade process is recommended. Please, refer to the [official guide](https://cassandra.apache.org/doc/latest/operating/backups.html#snapshots) for further information. + +### To 10.0.0 + +This major bump changes the following security defaults: + +- `runAsGroup` is changed from `0` to `1001` +- `readOnlyRootFilesystem` is set to `true` +- `resourcesPreset` is changed from `none` to the minimum size working in our test suites (NOTE: `resourcesPreset` is not meant for production usage, but `resources` adapted to your use case). +- `global.compatibility.openshift.adaptSecurityContext` is changed from `disabled` to `auto`. + +This could potentially break any customization or init scripts used in your deployment. If this is the case, change the default values to the previous ones. + +### To 9.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: + +- `serviceMonitor.labels` renamed as `serviceMonitor.selector`. +- `service.port` renamed as `service.ports.cql`. +- `service.metricsPort` renamed as `service.ports.metrics`. +- `service.nodePort` renamed as `service.nodePorts.cql`. +- `updateStrategy` changed from String type (previously default to 'rollingUpdate') to Object type, allowing users to configure other updateStrategy parameters, similar to other charts. +- Removed value `rollingUpdatePartition`, now configured using `updateStrategy` setting `updateStrategy.rollingUpdate.partition`. + +### To 8.0.0 + +Cassandra's version was bumped to `4.0`, [the new major](https://cassandra.apache.org/_/blog/Apache-Cassandra-4.0-is-Here.html) considered LTS. Among other features, this release removes support for [Thrift](https://issues.apache.org/jira/browse/CASSANDRA-11115), which means that the following properties of the chart will no longer be available: + +- `cluster.enableRPC` +- `service.thriftPort` +- `service.nodePorts.thrift` +- `containerPorts.thrift` + +For this version, there have been [intensive efforts](https://cwiki.apache.org/confluence/display/CASSANDRA/4.0+Quality%3A+Components+and+Test+Plans) from Apache to ensure that a safe cluster upgrade can be performed. Nevertheless, a backup creation prior to undergoing the upgrade process is recommended. Please, refer to the [official guide](https://cassandra.apache.org/doc/latest/operating/backups.html#snapshots) for further information. + +### To 7.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. + +### To 6.0.0 + +- Several parameters were renamed or disappeared in favor of new ones on this major version: + - `securityContext.*` is deprecated in favor of `podSecurityContext` and `containerSecurityContext`. + - Parameters prefixed with `statefulset.` were renamed removing the prefix. E.g. `statefulset.rollingUpdatePartition` -> renamed to `rollingUpdatePartition`. + - `cluster.replicaCount` is renamed to `replicaCount`. + - `cluster.domain` is renamed to `clusterDomain`. +- 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 `6.0.0`, install a new release of the Cassandra chart, and migrate the data from your previous release. To do so, create an snapshot of the database, and restore it on the new database. Check [this guide](https://cassandra.apache.org/doc/latest/operating/backups.html#snapshots) for more information. + +### To 5.4.0 + +The `minimumAvailable` option has been renamed to `minAvailable` for consistency with other charts. This is not a breaking change as `minimumAvailable` never worked before because of an error in chart templates. + +### To 5.0.0 + +An issue in StatefulSet manifest of the 4.x chart series rendered chart upgrades to be broken. The 5.0.0 series fixes this issue. To upgrade to the 5.x series you need to manually delete the Cassandra StatefulSet before executing the `helm upgrade` command. + +```console +kubectl delete sts -l release= +helm upgrade ... +``` + +### To 4.0.0 + +This release changes uses Bitnami Cassandra container `3.11.4-debian-9-r188`, based on Bash. + +### To 2.0.0 + +This release make it possible to specify custom initialization scripts in both cql and sh files. + +#### Breaking changes + +- `startupCQL` has been removed. Instead, for initializing the database, see [this section](#initialize-the-database). + +## License + +Copyright © 2025 Broadcom. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + +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 + + + +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/cassandra/charts/common/.helmignore b/cassandra/charts/common/.helmignore new file mode 100644 index 0000000..d0e1084 --- /dev/null +++ b/cassandra/charts/common/.helmignore @@ -0,0 +1,26 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ +# img folder +img/ +# Changelog +CHANGELOG.md diff --git a/cassandra/charts/common/Chart.yaml b/cassandra/charts/common/Chart.yaml new file mode 100644 index 0000000..10fc86a --- /dev/null +++ b/cassandra/charts/common/Chart.yaml @@ -0,0 +1,23 @@ +annotations: + category: Infrastructure + licenses: Apache-2.0 +apiVersion: v2 +appVersion: 2.30.0 +description: A Library Helm Chart for grouping common logic between bitnami charts. + This chart is not deployable by itself. +home: https://bitnami.com +icon: https://dyltqmyl993wv.cloudfront.net/downloads/logos/bitnami-mark.png +keywords: +- common +- helper +- template +- function +- bitnami +maintainers: +- name: Broadcom, Inc. All Rights Reserved. + url: https://github.com/bitnami/charts +name: common +sources: +- https://github.com/bitnami/charts/tree/main/bitnami/common +type: library +version: 2.30.0 diff --git a/cassandra/charts/common/README.md b/cassandra/charts/common/README.md new file mode 100644 index 0000000..0e5f649 --- /dev/null +++ b/cassandra/charts/common/README.md @@ -0,0 +1,235 @@ +# 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: 2.x.x + repository: oci://registry-1.docker.io/bitnamicharts +``` + +```console +helm dependency update +``` + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "common.names.fullname" . }} +data: + myvalue: "Hello World" +``` + +Looking to use our applications in production? Try [VMware Tanzu Application Catalog](https://bitnami.com/enterprise), the commercial edition of the Bitnami catalog. + +## 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.23+ +- Helm 3.8.0+ + +## Parameters + +## 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.' + +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 + +- +- +- + +## License + +Copyright © 2025 Broadcom. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + +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 + + + +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/cassandra/charts/common/templates/_affinities.tpl b/cassandra/charts/common/templates/_affinities.tpl new file mode 100644 index 0000000..d387dbe --- /dev/null +++ b/cassandra/charts/common/templates/_affinities.tpl @@ -0,0 +1,155 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.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" "customLabels" .Values.podLabels "extraMatchLabels" .Values.extraMatchLabels "topologyKey" "BAR" "extraPodAffinityTerms" .Values.extraPodAffinityTerms "extraNamespaces" (list "namespace1" "namespace2") "context" $) -}} +*/}} +{{- define "common.affinities.pods.soft" -}} +{{- $component := default "" .component -}} +{{- $customLabels := default (dict) .customLabels -}} +{{- $extraMatchLabels := default (dict) .extraMatchLabels -}} +{{- $extraPodAffinityTerms := default (list) .extraPodAffinityTerms -}} +{{- $extraNamespaces := default (list) .extraNamespaces -}} +preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" ( dict "customLabels" $customLabels "context" .context )) | nindent 10 }} + {{- if not (empty $component) }} + {{ printf "app.kubernetes.io/component: %s" $component }} + {{- end }} + {{- range $key, $value := $extraMatchLabels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- if $extraNamespaces }} + namespaces: + - {{ .context.Release.Namespace }} + {{- with $extraNamespaces }} + {{ include "common.tplvalues.render" (dict "value" . "context" $) | nindent 8 }} + {{- end }} + {{- end }} + topologyKey: {{ include "common.affinities.topologyKey" (dict "topologyKey" .topologyKey) }} + weight: 1 + {{- range $extraPodAffinityTerms }} + - podAffinityTerm: + labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" ( dict "customLabels" $customLabels "context" $.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: {{ .weight | default 1 -}} + {{- end -}} +{{- end -}} + +{{/* +Return a hard podAffinity/podAntiAffinity definition +{{ include "common.affinities.pods.hard" (dict "component" "FOO" "customLabels" .Values.podLabels "extraMatchLabels" .Values.extraMatchLabels "topologyKey" "BAR" "extraPodAffinityTerms" .Values.extraPodAffinityTerms "extraNamespaces" (list "namespace1" "namespace2") "context" $) -}} +*/}} +{{- define "common.affinities.pods.hard" -}} +{{- $component := default "" .component -}} +{{- $customLabels := default (dict) .customLabels -}} +{{- $extraMatchLabels := default (dict) .extraMatchLabels -}} +{{- $extraPodAffinityTerms := default (list) .extraPodAffinityTerms -}} +{{- $extraNamespaces := default (list) .extraNamespaces -}} +requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" ( dict "customLabels" $customLabels "context" .context )) | nindent 8 }} + {{- if not (empty $component) }} + {{ printf "app.kubernetes.io/component: %s" $component }} + {{- end }} + {{- range $key, $value := $extraMatchLabels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- if $extraNamespaces }} + namespaces: + - {{ .context.Release.Namespace }} + {{- with $extraNamespaces }} + {{ include "common.tplvalues.render" (dict "value" . "context" $) | nindent 8 }} + {{- end }} + {{- end }} + topologyKey: {{ include "common.affinities.topologyKey" (dict "topologyKey" .topologyKey) }} + {{- range $extraPodAffinityTerms }} + - labelSelector: + matchLabels: {{- (include "common.labels.matchLabels" ( dict "customLabels" $customLabels "context" $.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 -}} +{{- 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/cassandra/charts/common/templates/_capabilities.tpl b/cassandra/charts/common/templates/_capabilities.tpl new file mode 100644 index 0000000..6423fb1 --- /dev/null +++ b/cassandra/charts/common/templates/_capabilities.tpl @@ -0,0 +1,253 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} + +{{/* +Return the target Kubernetes version +*/}} +{{- define "common.capabilities.kubeVersion" -}} +{{- default (default .Capabilities.KubeVersion.Version .Values.kubeVersion) ((.Values.global).kubeVersion) -}} +{{- end -}} + +{{/* +Return true if the apiVersion is supported +Usage: +{{ include "common.capabilities.apiVersions.has" (dict "version" "batch/v1" "context" $) }} +*/}} +{{- define "common.capabilities.apiVersions.has" -}} +{{- $providedAPIVersions := default .context.Values.apiVersions ((.context.Values.global).apiVersions) -}} +{{- if and (empty $providedAPIVersions) (.context.Capabilities.APIVersions.Has .version) -}} + {{- true -}} +{{- else if has .version $providedAPIVersions -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for poddisruptionbudget. +*/}} +{{- define "common.capabilities.policy.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.21-0" $kubeVersion) -}} +{{- print "policy/v1beta1" -}} +{{- else -}} +{{- print "policy/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for networkpolicy. +*/}} +{{- define "common.capabilities.networkPolicy.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.7-0" $kubeVersion) -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "networking.k8s.io/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for job. +*/}} +{{- define "common.capabilities.job.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.21-0" $kubeVersion) -}} +{{- print "batch/v1beta1" -}} +{{- else -}} +{{- print "batch/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for cronjob. +*/}} +{{- define "common.capabilities.cronjob.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.21-0" $kubeVersion) -}} +{{- print "batch/v1beta1" -}} +{{- else -}} +{{- print "batch/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for daemonset. +*/}} +{{- define "common.capabilities.daemonset.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.14-0" $kubeVersion) -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for deployment. +*/}} +{{- define "common.capabilities.deployment.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.14-0" $kubeVersion) -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for statefulset. +*/}} +{{- define "common.capabilities.statefulset.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.14-0" $kubeVersion) -}} +{{- print "apps/v1beta1" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for ingress. +*/}} +{{- define "common.capabilities.ingress.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if (.Values.ingress).apiVersion -}} +{{- .Values.ingress.apiVersion -}} +{{- else if and (not (empty $kubeVersion)) (semverCompare "<1.14-0" $kubeVersion) -}} +{{- print "extensions/v1beta1" -}} +{{- else if and (not (empty $kubeVersion)) (semverCompare "<1.19-0" $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" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.17-0" $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" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.19-0" $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" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.10-0" $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" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" .context -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.23-0" $kubeVersion) -}} +{{- if .beta2 -}} +{{- print "autoscaling/v2beta2" -}} +{{- else -}} +{{- print "autoscaling/v2beta1" -}} +{{- end -}} +{{- else -}} +{{- print "autoscaling/v2" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for Vertical Pod Autoscaler. +*/}} +{{- define "common.capabilities.vpa.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" .context -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.11-0" $kubeVersion) -}} +{{- print "autoscaling/v1beta1" -}} +{{- else if and (not (empty $kubeVersion)) (semverCompare "<1.25-0" $kubeVersion) -}} +{{- print "autoscaling/v1beta2" -}} +{{- else -}} +{{- print "autoscaling/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Returns true if PodSecurityPolicy is supported +*/}} +{{- define "common.capabilities.psp.supported" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if or (empty $kubeVersion) (semverCompare "<1.25-0" $kubeVersion) -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Returns true if AdmissionConfiguration is supported +*/}} +{{- define "common.capabilities.admissionConfiguration.supported" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if or (empty $kubeVersion) (not (semverCompare "<1.23-0" $kubeVersion)) -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for AdmissionConfiguration. +*/}} +{{- define "common.capabilities.admissionConfiguration.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.23-0" $kubeVersion) -}} +{{- print "apiserver.config.k8s.io/v1alpha1" -}} +{{- else if and (not (empty $kubeVersion)) (semverCompare "<1.25-0" $kubeVersion) -}} +{{- print "apiserver.config.k8s.io/v1beta1" -}} +{{- else -}} +{{- print "apiserver.config.k8s.io/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for PodSecurityConfiguration. +*/}} +{{- define "common.capabilities.podSecurityConfiguration.apiVersion" -}} +{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.23-0" $kubeVersion) -}} +{{- print "pod-security.admission.config.k8s.io/v1alpha1" -}} +{{- else if and (not (empty $kubeVersion)) (semverCompare "<1.25-0" $kubeVersion) -}} +{{- print "pod-security.admission.config.k8s.io/v1beta1" -}} +{{- else -}} +{{- print "pod-security.admission.config.k8s.io/v1" -}} +{{- 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/cassandra/charts/common/templates/_compatibility.tpl b/cassandra/charts/common/templates/_compatibility.tpl new file mode 100644 index 0000000..19c26db --- /dev/null +++ b/cassandra/charts/common/templates/_compatibility.tpl @@ -0,0 +1,46 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} + +{{/* +Return true if the detected platform is Openshift +Usage: +{{- include "common.compatibility.isOpenshift" . -}} +*/}} +{{- define "common.compatibility.isOpenshift" -}} +{{- if .Capabilities.APIVersions.Has "security.openshift.io/v1" -}} +{{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Render a compatible securityContext depending on the platform. By default it is maintained as it is. In other platforms like Openshift we remove default user/group values that do not work out of the box with the restricted-v1 SCC +Usage: +{{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.containerSecurityContext "context" $) -}} +*/}} +{{- define "common.compatibility.renderSecurityContext" -}} +{{- $adaptedContext := .secContext -}} + +{{- if (((.context.Values.global).compatibility).openshift) -}} + {{- if or (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "force") (and (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "auto") (include "common.compatibility.isOpenshift" .context)) -}} + {{/* Remove incompatible user/group values that do not work in Openshift out of the box */}} + {{- $adaptedContext = omit $adaptedContext "fsGroup" "runAsUser" "runAsGroup" -}} + {{- if not .secContext.seLinuxOptions -}} + {{/* If it is an empty object, we remove it from the resulting context because it causes validation issues */}} + {{- $adaptedContext = omit $adaptedContext "seLinuxOptions" -}} + {{- end -}} + {{- end -}} +{{- end -}} +{{/* Remove empty seLinuxOptions object if global.compatibility.omitEmptySeLinuxOptions is set to true */}} +{{- if and (((.context.Values.global).compatibility).omitEmptySeLinuxOptions) (not .secContext.seLinuxOptions) -}} + {{- $adaptedContext = omit $adaptedContext "seLinuxOptions" -}} +{{- end -}} +{{/* Remove fields that are disregarded when running the container in privileged mode */}} +{{- if $adaptedContext.privileged -}} + {{- $adaptedContext = omit $adaptedContext "capabilities" -}} +{{- end -}} +{{- omit $adaptedContext "enabled" | toYaml -}} +{{- end -}} diff --git a/cassandra/charts/common/templates/_errors.tpl b/cassandra/charts/common/templates/_errors.tpl new file mode 100644 index 0000000..93f3ffc --- /dev/null +++ b/cassandra/charts/common/templates/_errors.tpl @@ -0,0 +1,85 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Throw 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 -}} + +{{/* +Throw error when original container images are replaced. +The error can be bypassed by setting the "global.security.allowInsecureImages" to true. In this case, +a warning message will be shown instead. + +Usage: +{{ include "common.errors.insecureImages" (dict "images" (list .Values.path.to.the.imageRoot) "context" $) }} +*/}} +{{- define "common.errors.insecureImages" -}} +{{- $relocatedImages := list -}} +{{- $replacedImages := list -}} +{{- $retaggedImages := list -}} +{{- $globalRegistry := ((.context.Values.global).imageRegistry) -}} +{{- $originalImages := .context.Chart.Annotations.images -}} +{{- range .images -}} + {{- $registryName := default .registry $globalRegistry -}} + {{- $fullImageNameNoTag := printf "%s/%s" $registryName .repository -}} + {{- $fullImageName := printf "%s:%s" $fullImageNameNoTag .tag -}} + {{- if not (contains $fullImageNameNoTag $originalImages) -}} + {{- if not (contains $registryName $originalImages) -}} + {{- $relocatedImages = append $relocatedImages $fullImageName -}} + {{- else if not (contains .repository $originalImages) -}} + {{- $replacedImages = append $replacedImages $fullImageName -}} + {{- end -}} + {{- end -}} + {{- if not (contains (printf "%s:%s" .repository .tag) $originalImages) -}} + {{- $retaggedImages = append $retaggedImages $fullImageName -}} + {{- end -}} +{{- end -}} + +{{- if and (or (gt (len $relocatedImages) 0) (gt (len $replacedImages) 0)) (((.context.Values.global).security).allowInsecureImages) -}} + {{- print "\n\n⚠ SECURITY WARNING: Verifying original container images was skipped. Please note this Helm chart was designed, tested, and validated on multiple platforms using a specific set of Bitnami and Tanzu Application Catalog containers. Substituting other containers is likely to cause degraded security and performance, broken chart features, and missing environment variables.\n" -}} +{{- else if (or (gt (len $relocatedImages) 0) (gt (len $replacedImages) 0)) -}} + {{- $errorString := "Original containers have been substituted for unrecognized ones. Deploying this chart with non-standard containers is likely to cause degraded security and performance, broken chart features, and missing environment variables." -}} + {{- $errorString = print $errorString "\n\nUnrecognized images:" -}} + {{- range (concat $relocatedImages $replacedImages) -}} + {{- $errorString = print $errorString "\n - " . -}} + {{- end -}} + {{- if or (contains "docker.io/bitnami/" $originalImages) (contains "docker.io/bitnamiprem/" $originalImages) -}} + {{- $errorString = print "\n\n⚠ ERROR: " $errorString -}} + {{- $errorString = print $errorString "\n\nIf you are sure you want to proceed with non-standard containers, you can skip container image verification by setting the global parameter 'global.security.allowInsecureImages' to true." -}} + {{- $errorString = print $errorString "\nFurther information can be obtained at https://github.com/bitnami/charts/issues/30850" -}} + {{- print $errorString | fail -}} + {{- else if gt (len $replacedImages) 0 -}} + {{- $errorString = print "\n\n⚠ WARNING: " $errorString -}} + {{- print $errorString -}} + {{- end -}} +{{- else if gt (len $retaggedImages) 0 -}} + {{- $warnString := "\n\n⚠ WARNING: Original containers have been retagged. Please note this Helm chart was tested, and validated on multiple platforms using a specific set of Tanzu Application Catalog containers. Substituting original image tags could cause unexpected behavior." -}} + {{- $warnString = print $warnString "\n\nRetagged images:" -}} + {{- range $retaggedImages -}} + {{- $warnString = print $warnString "\n - " . -}} + {{- end -}} + {{- print $warnString -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/cassandra/charts/common/templates/_images.tpl b/cassandra/charts/common/templates/_images.tpl new file mode 100644 index 0000000..d1250b7 --- /dev/null +++ b/cassandra/charts/common/templates/_images.tpl @@ -0,0 +1,115 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Return the proper image name. +If image tag and digest are not defined, termination fallbacks to chart appVersion. +{{ include "common.images.image" ( dict "imageRoot" .Values.path.to.the.image "global" .Values.global "chart" .Chart ) }} +*/}} +{{- define "common.images.image" -}} +{{- $registryName := default .imageRoot.registry ((.global).imageRegistry) -}} +{{- $repositoryName := .imageRoot.repository -}} +{{- $separator := ":" -}} +{{- $termination := .imageRoot.tag | toString -}} + +{{- if not .imageRoot.tag }} + {{- if .chart }} + {{- $termination = .chart.AppVersion | toString -}} + {{- end -}} +{{- end -}} +{{- if .imageRoot.digest }} + {{- $separator = "@" -}} + {{- $termination = .imageRoot.digest | toString -}} +{{- end -}} +{{- if $registryName }} + {{- printf "%s/%s%s%s" $registryName $repositoryName $separator $termination -}} +{{- else -}} + {{- printf "%s%s%s" $repositoryName $separator $termination -}} +{{- end -}} +{{- 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 }} + + {{- range ((.global).imagePullSecrets) -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets .name -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets . -}} + {{- end }} + {{- end -}} + + {{- range .images -}} + {{- range .pullSecrets -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets .name -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets . -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- if (not (empty $pullSecrets)) -}} +imagePullSecrets: + {{- range $pullSecrets | uniq }} + - 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 }} + + {{- range (($context.Values.global).imagePullSecrets) -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" $context)) -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" $context)) -}} + {{- end -}} + {{- end -}} + + {{- range .images -}} + {{- range .pullSecrets -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" $context)) -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" $context)) -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- if (not (empty $pullSecrets)) -}} +imagePullSecrets: + {{- range $pullSecrets | uniq }} + - name: {{ . }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Return the proper image version (ingores image revision/prerelease info & fallbacks to chart appVersion) +{{ include "common.images.version" ( dict "imageRoot" .Values.path.to.the.image "chart" .Chart ) }} +*/}} +{{- define "common.images.version" -}} +{{- $imageTag := .imageRoot.tag | toString -}} +{{/* regexp from https://github.com/mainminds/semver/blob/23f51de38a0866c5ef0bfc42b3f735c73107b700/version.go#L41-L44 */}} +{{- if regexMatch `^([0-9]+)(\.[0-9]+)?(\.[0-9]+)?(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?$` $imageTag -}} + {{- $version := semver $imageTag -}} + {{- printf "%d.%d.%d" $version.Major $version.Minor $version.Patch -}} +{{- else -}} + {{- print .chart.AppVersion -}} +{{- end -}} +{{- end -}} + diff --git a/cassandra/charts/common/templates/_ingress.tpl b/cassandra/charts/common/templates/_ingress.tpl new file mode 100644 index 0000000..7d2b879 --- /dev/null +++ b/cassandra/charts/common/templates/_ingress.tpl @@ -0,0 +1,73 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.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/cassandra/charts/common/templates/_labels.tpl b/cassandra/charts/common/templates/_labels.tpl new file mode 100644 index 0000000..0a0cc54 --- /dev/null +++ b/cassandra/charts/common/templates/_labels.tpl @@ -0,0 +1,46 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} + +{{/* +Kubernetes standard labels +{{ include "common.labels.standard" (dict "customLabels" .Values.commonLabels "context" $) -}} +*/}} +{{- define "common.labels.standard" -}} +{{- if and (hasKey . "customLabels") (hasKey . "context") -}} +{{- $default := dict "app.kubernetes.io/name" (include "common.names.name" .context) "helm.sh/chart" (include "common.names.chart" .context) "app.kubernetes.io/instance" .context.Release.Name "app.kubernetes.io/managed-by" .context.Release.Service -}} +{{- with .context.Chart.AppVersion -}} +{{- $_ := set $default "app.kubernetes.io/version" . -}} +{{- end -}} +{{ template "common.tplvalues.merge" (dict "values" (list .customLabels $default) "context" .context) }} +{{- else -}} +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 }} +{{- with .Chart.AppVersion }} +app.kubernetes.io/version: {{ . | quote }} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Labels used on immutable fields such as deploy.spec.selector.matchLabels or svc.spec.selector +{{ include "common.labels.matchLabels" (dict "customLabels" .Values.podLabels "context" $) -}} + +We don't want to loop over custom labels appending them to the selector +since it's very likely that it will break deployments, services, etc. +However, it's important to overwrite the standard labels if the user +overwrote them on metadata.labels fields. +*/}} +{{- define "common.labels.matchLabels" -}} +{{- if and (hasKey . "customLabels") (hasKey . "context") -}} +{{ merge (pick (include "common.tplvalues.render" (dict "value" .customLabels "context" .context) | fromYaml) "app.kubernetes.io/name" "app.kubernetes.io/instance") (dict "app.kubernetes.io/name" (include "common.names.name" .context) "app.kubernetes.io/instance" .context.Release.Name ) | toYaml }} +{{- else -}} +app.kubernetes.io/name: {{ include "common.names.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} +{{- end -}} diff --git a/cassandra/charts/common/templates/_names.tpl b/cassandra/charts/common/templates/_names.tpl new file mode 100644 index 0000000..ba83956 --- /dev/null +++ b/cassandra/charts/common/templates/_names.tpl @@ -0,0 +1,71 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.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/cassandra/charts/common/templates/_resources.tpl b/cassandra/charts/common/templates/_resources.tpl new file mode 100644 index 0000000..d8a43e1 --- /dev/null +++ b/cassandra/charts/common/templates/_resources.tpl @@ -0,0 +1,50 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} + +{{/* +Return a resource request/limit object based on a given preset. +These presets are for basic testing and not meant to be used in production +{{ include "common.resources.preset" (dict "type" "nano") -}} +*/}} +{{- define "common.resources.preset" -}} +{{/* The limits are the requests increased by 50% (except ephemeral-storage and xlarge/2xlarge sizes)*/}} +{{- $presets := dict + "nano" (dict + "requests" (dict "cpu" "100m" "memory" "128Mi" "ephemeral-storage" "50Mi") + "limits" (dict "cpu" "150m" "memory" "192Mi" "ephemeral-storage" "2Gi") + ) + "micro" (dict + "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") + "limits" (dict "cpu" "375m" "memory" "384Mi" "ephemeral-storage" "2Gi") + ) + "small" (dict + "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") + "limits" (dict "cpu" "750m" "memory" "768Mi" "ephemeral-storage" "2Gi") + ) + "medium" (dict + "requests" (dict "cpu" "500m" "memory" "1024Mi" "ephemeral-storage" "50Mi") + "limits" (dict "cpu" "750m" "memory" "1536Mi" "ephemeral-storage" "2Gi") + ) + "large" (dict + "requests" (dict "cpu" "1.0" "memory" "2048Mi" "ephemeral-storage" "50Mi") + "limits" (dict "cpu" "1.5" "memory" "3072Mi" "ephemeral-storage" "2Gi") + ) + "xlarge" (dict + "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") + "limits" (dict "cpu" "3.0" "memory" "6144Mi" "ephemeral-storage" "2Gi") + ) + "2xlarge" (dict + "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") + "limits" (dict "cpu" "6.0" "memory" "12288Mi" "ephemeral-storage" "2Gi") + ) + }} +{{- if hasKey $presets .type -}} +{{- index $presets .type | toYaml -}} +{{- else -}} +{{- printf "ERROR: Preset key '%s' invalid. Allowed values are %s" .type (join "," (keys $presets)) | fail -}} +{{- end -}} +{{- end -}} diff --git a/cassandra/charts/common/templates/_secrets.tpl b/cassandra/charts/common/templates/_secrets.tpl new file mode 100644 index 0000000..bfef469 --- /dev/null +++ b/cassandra/charts/common/templates/_secrets.tpl @@ -0,0 +1,192 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.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" "honorProvidedValues" false "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. + - failOnNew - Boolean - Optional - Default to true. If set to false, skip errors adding new keys to existing secrets. + - skipB64enc - Boolean - Optional - Default to false. If set to true, no the secret will not be base64 encrypted. + - skipQuote - Boolean - Optional - Default to false. If set to true, no quotes will be added around the secret. + - honorProvidedValues - Boolean - Optional - Default to false. If set to true, the values in providedValues have higher priority than an existing secret +The order in which this function returns a secret password: + 1. Password provided via the values.yaml if honorProvidedValues = true + (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) + 2. 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) + 3. Password provided via the values.yaml if honorProvidedValues = false + (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) + 4. 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 | b64dec }} + {{- else if not (eq .failOnNew false) }} + {{- printf "\nPASSWORDS ERROR: The secret \"%s\" does not contain the key \"%s\"\n" .secret .key | fail -}} + {{- end -}} +{{- end }} + +{{- if and $providedPasswordValue .honorProvidedValues }} + {{- $password = $providedPasswordValue | toString }} +{{- end }} + +{{- if not $password }} + {{- if $providedPasswordValue }} + {{- $password = $providedPasswordValue | toString }} + {{- else }} + {{- if .context.Values.enabled }} + {{- $subchart = $chartName }} + {{- end -}} + + {{- if not (eq .failOnNew false) }} + {{- $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) -}} + {{- end }} + + {{- 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 }} + {{- else }} + {{- $password = randAlphaNum $passwordLength }} + {{- end }} + {{- end -}} +{{- end -}} +{{- if not .skipB64enc }} +{{- $password = $password | b64enc }} +{{- end -}} +{{- if .skipQuote -}} +{{- printf "%s" $password -}} +{{- else -}} +{{- printf "%s" $password | quote -}} +{{- end -}} +{{- 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 := "" -}} +{{- $secretData := (lookup "v1" "Secret" (include "common.names.namespace" .context) .secret).data -}} +{{- if and $secretData (hasKey $secretData .key) -}} + {{- $value = index $secretData .key -}} +{{- else if .defaultValue -}} + {{- $value = .defaultValue | toString | b64enc -}} +{{- end -}} +{{- if $value -}} +{{- printf "%s" $value -}} +{{- end -}} +{{- 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/cassandra/charts/common/templates/_storage.tpl b/cassandra/charts/common/templates/_storage.tpl new file mode 100644 index 0000000..aa75856 --- /dev/null +++ b/cassandra/charts/common/templates/_storage.tpl @@ -0,0 +1,21 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.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 := (.global).storageClass | default .persistence.storageClass | default (.global).defaultStorageClass | default "" -}} +{{- if $storageClass -}} + {{- if (eq "-" $storageClass) -}} + {{- printf "storageClassName: \"\"" -}} + {{- else -}} + {{- printf "storageClassName: %s" $storageClass -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/cassandra/charts/common/templates/_tplvalues.tpl b/cassandra/charts/common/templates/_tplvalues.tpl new file mode 100644 index 0000000..06bd1ac --- /dev/null +++ b/cassandra/charts/common/templates/_tplvalues.tpl @@ -0,0 +1,52 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Renders a value that contains template perhaps with scope if the scope is present. +Usage: +{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $ ) }} +{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $ "scope" $app ) }} +*/}} +{{- define "common.tplvalues.render" -}} +{{- $value := typeIs "string" .value | ternary .value (.value | toYaml) }} +{{- if contains "{{" (toJson .value) }} + {{- if .scope }} + {{- tpl (cat "{{- with $.RelativeScope -}}" $value "{{- end }}") (merge (dict "RelativeScope" .scope) .context) }} + {{- else }} + {{- tpl $value .context }} + {{- end }} +{{- else }} + {{- $value }} +{{- end }} +{{- end -}} + +{{/* +Merge a list of values that contains template after rendering them. +Merge precedence is consistent with http://mainminds.github.io/sprig/dicts.html#merge-mustmerge +Usage: +{{ include "common.tplvalues.merge" ( dict "values" (list .Values.path.to.the.Value1 .Values.path.to.the.Value2) "context" $ ) }} +*/}} +{{- define "common.tplvalues.merge" -}} +{{- $dst := dict -}} +{{- range .values -}} +{{- $dst = include "common.tplvalues.render" (dict "value" . "context" $.context "scope" $.scope) | fromYaml | merge $dst -}} +{{- end -}} +{{ $dst | toYaml }} +{{- end -}} + +{{/* +Merge a list of values that contains template after rendering them. +Merge precedence is consistent with https://mainminds.github.io/sprig/dicts.html#mergeoverwrite-mustmergeoverwrite +Usage: +{{ include "common.tplvalues.merge-overwrite" ( dict "values" (list .Values.path.to.the.Value1 .Values.path.to.the.Value2) "context" $ ) }} +*/}} +{{- define "common.tplvalues.merge-overwrite" -}} +{{- $dst := dict -}} +{{- range .values -}} +{{- $dst = include "common.tplvalues.render" (dict "value" . "context" $.context "scope" $.scope) | fromYaml | mergeOverwrite $dst -}} +{{- end -}} +{{ $dst | toYaml }} +{{- end -}} diff --git a/cassandra/charts/common/templates/_utils.tpl b/cassandra/charts/common/templates/_utils.tpl new file mode 100644 index 0000000..d53c74a --- /dev/null +++ b/cassandra/charts/common/templates/_utils.tpl @@ -0,0 +1,77 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.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 -}} + +{{/* +Checksum a template at "path" containing a *single* resource (ConfigMap,Secret) for use in pod annotations, excluding the metadata (see #18376). +Usage: +{{ include "common.utils.checksumTemplate" (dict "path" "/configmap.yaml" "context" $) }} +*/}} +{{- define "common.utils.checksumTemplate" -}} +{{- $obj := include (print .context.Template.BasePath .path) .context | fromYaml -}} +{{ omit $obj "apiVersion" "kind" "metadata" | toYaml | sha256sum }} +{{- end -}} diff --git a/cassandra/charts/common/templates/_warnings.tpl b/cassandra/charts/common/templates/_warnings.tpl new file mode 100644 index 0000000..62c44df --- /dev/null +++ b/cassandra/charts/common/templates/_warnings.tpl @@ -0,0 +1,109 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.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://techdocs.broadcom.com/us/en/vmware-tanzu/application-catalog/tanzu-application-catalog/services/tac-doc/apps-tutorials-understand-rolling-tags-containers-index.html +{{- end }} +{{- end -}} + +{{/* +Warning about replaced images from the original. +Usage: +{{ include "common.warnings.modifiedImages" (dict "images" (list .Values.path.to.the.imageRoot) "context" $) }} +*/}} +{{- define "common.warnings.modifiedImages" -}} +{{- $affectedImages := list -}} +{{- $printMessage := false -}} +{{- $originalImages := .context.Chart.Annotations.images -}} +{{- range .images -}} + {{- $fullImageName := printf (printf "%s/%s:%s" .registry .repository .tag) -}} + {{- if not (contains $fullImageName $originalImages) }} + {{- $affectedImages = append $affectedImages (printf "%s/%s:%s" .registry .repository .tag) -}} + {{- $printMessage = true -}} + {{- end -}} +{{- end -}} +{{- if $printMessage }} + +⚠ SECURITY WARNING: Original containers have been substituted. This Helm chart was designed, tested, and validated on multiple platforms using a specific set of Bitnami and Tanzu Application Catalog containers. Substituting other containers is likely to cause degraded security and performance, broken chart features, and missing environment variables. + +Substituted images detected: +{{- range $affectedImages }} + - {{ . }} +{{- end }} +{{- end -}} +{{- end -}} + +{{/* +Warning about not setting the resource object in all deployments. +Usage: +{{ include "common.warnings.resources" (dict "sections" (list "path1" "path2") context $) }} +Example: +{{- include "common.warnings.resources" (dict "sections" (list "csiProvider.provider" "server" "volumePermissions" "") "context" $) }} +The list in the example assumes that the following values exist: + - csiProvider.provider.resources + - server.resources + - volumePermissions.resources + - resources +*/}} +{{- define "common.warnings.resources" -}} +{{- $values := .context.Values -}} +{{- $printMessage := false -}} +{{ $affectedSections := list -}} +{{- range .sections -}} + {{- if eq . "" -}} + {{/* Case where the resources section is at the root (one main deployment in the chart) */}} + {{- if not (index $values "resources") -}} + {{- $affectedSections = append $affectedSections "resources" -}} + {{- $printMessage = true -}} + {{- end -}} + {{- else -}} + {{/* Case where the are multiple resources sections (more than one main deployment in the chart) */}} + {{- $keys := split "." . -}} + {{/* We iterate through the different levels until arriving to the resource section. Example: a.b.c.resources */}} + {{- $section := $values -}} + {{- range $keys -}} + {{- $section = index $section . -}} + {{- end -}} + {{- if not (index $section "resources") -}} + {{/* If the section has enabled=false or replicaCount=0, do not include it */}} + {{- if and (hasKey $section "enabled") -}} + {{- if index $section "enabled" -}} + {{/* enabled=true */}} + {{- $affectedSections = append $affectedSections (printf "%s.resources" .) -}} + {{- $printMessage = true -}} + {{- end -}} + {{- else if and (hasKey $section "replicaCount") -}} + {{/* We need a casting to int because number 0 is not treated as an int by default */}} + {{- if (gt (index $section "replicaCount" | int) 0) -}} + {{/* replicaCount > 0 */}} + {{- $affectedSections = append $affectedSections (printf "%s.resources" .) -}} + {{- $printMessage = true -}} + {{- end -}} + {{- else -}} + {{/* Default case, add it to the affected sections */}} + {{- $affectedSections = append $affectedSections (printf "%s.resources" .) -}} + {{- $printMessage = true -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} +{{- if $printMessage }} + +WARNING: There are "resources" sections in the chart not set. Using "resourcesPreset" is not recommended for production. For production installations, please set the following values according to your workload needs: +{{- range $affectedSections }} + - {{ . }} +{{- end }} ++info https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +{{- end -}} +{{- end -}} diff --git a/cassandra/charts/common/templates/validations/_cassandra.tpl b/cassandra/charts/common/templates/validations/_cassandra.tpl new file mode 100644 index 0000000..f8fd213 --- /dev/null +++ b/cassandra/charts/common/templates/validations/_cassandra.tpl @@ -0,0 +1,51 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +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/cassandra/charts/common/templates/validations/_mariadb.tpl b/cassandra/charts/common/templates/validations/_mariadb.tpl new file mode 100644 index 0000000..6ea8c0f --- /dev/null +++ b/cassandra/charts/common/templates/validations/_mariadb.tpl @@ -0,0 +1,108 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.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/cassandra/charts/common/templates/validations/_mongodb.tpl b/cassandra/charts/common/templates/validations/_mongodb.tpl new file mode 100644 index 0000000..e678a6d --- /dev/null +++ b/cassandra/charts/common/templates/validations/_mongodb.tpl @@ -0,0 +1,67 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +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/cassandra/charts/common/templates/validations/_mysql.tpl b/cassandra/charts/common/templates/validations/_mysql.tpl new file mode 100644 index 0000000..fbb65c3 --- /dev/null +++ b/cassandra/charts/common/templates/validations/_mysql.tpl @@ -0,0 +1,67 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +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/cassandra/charts/common/templates/validations/_postgresql.tpl b/cassandra/charts/common/templates/validations/_postgresql.tpl new file mode 100644 index 0000000..51d4716 --- /dev/null +++ b/cassandra/charts/common/templates/validations/_postgresql.tpl @@ -0,0 +1,105 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} +{{/* +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/cassandra/charts/common/templates/validations/_redis.tpl b/cassandra/charts/common/templates/validations/_redis.tpl new file mode 100644 index 0000000..9fedfef --- /dev/null +++ b/cassandra/charts/common/templates/validations/_redis.tpl @@ -0,0 +1,48 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + + +{{/* vim: set filetype=mustache: */}} +{{/* +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/cassandra/charts/common/templates/validations/_validations.tpl b/cassandra/charts/common/templates/validations/_validations.tpl new file mode 100644 index 0000000..7cdee61 --- /dev/null +++ b/cassandra/charts/common/templates/validations/_validations.tpl @@ -0,0 +1,51 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.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/cassandra/charts/common/values.yaml b/cassandra/charts/common/values.yaml new file mode 100644 index 0000000..de2cac5 --- /dev/null +++ b/cassandra/charts/common/values.yaml @@ -0,0 +1,8 @@ +# Copyright Broadcom, Inc. All Rights Reserved. +# SPDX-License-Identifier: APACHE-2.0 + +## bitnami/common +## It is required by CI/CD tools and processes. +## @skip exampleValue +## +exampleValue: common-chart diff --git a/cassandra/templates/NOTES.txt b/cassandra/templates/NOTES.txt new file mode 100644 index 0000000..b4765ef --- /dev/null +++ b/cassandra/templates/NOTES.txt @@ -0,0 +1,96 @@ +CHART NAME: {{ .Chart.Name }} +CHART VERSION: {{ .Chart.Version }} +APP VERSION: {{ .Chart.AppVersion }} + +Did you know there are enterprise versions of the Bitnami catalog? For enhanced secure software supply chain features, unlimited pulls from Docker, LTS support, or application customization, see Bitnami Premium or Tanzu Application Catalog. See https://www.arrow.com/globalecs/na/vendors/bitnami for more information. + +{{- $cassandraPasswordKey := ( include "common.secrets.key" (dict "existingSecret" .Values.dbUser.existingSecret "key" "cassandra-password") ) -}} +{{- $cassandraSecretName := ( include "common.secrets.name" (dict "existingSecret" .Values.dbUser.existingSecret "context" $) ) -}} + +** 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/cassandra/entrypoint.sh /opt/bitnami/scripts/cassandra/run.sh + +{{- else }} + +Cassandra can be accessed through the following URLs from within the cluster: + + - CQL: {{ include "common.names.fullname" . }}.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }}:{{ .Values.service.ports.cql }} + +To get your password run: + + {{ include "common.utils.secret.getvalue" (dict "secret" $cassandraSecretName "field" $cassandraPasswordKey "context" $) }} + +Check the cluster status by running: + + kubectl exec -it --namespace {{ include "common.names.namespace" . }} $(kubectl get pods --namespace {{ include "common.names.namespace" . }} -l app.kubernetes.io/name={{ include "common.names.name" . }},app.kubernetes.io/instance={{ .Release.Name }} -o jsonpath='{.items[0].metadata.name}') nodetool status + +To connect to your Cassandra cluster using CQL: + +1. Run a Cassandra pod that you can use as a client: + + kubectl run --namespace {{ include "common.names.namespace" . }} {{ include "common.names.fullname" . }}-client --rm --tty -i --restart='Never' \ + --env CASSANDRA_PASSWORD=$CASSANDRA_PASSWORD \ + {{ if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }}--labels="{{ include "common.names.name" . }}-client=true"{{ end }} \ + --image {{ include "cassandra.image" . }} -- bash + +2. Connect using the cqlsh client: + + cqlsh -u {{ .Values.dbUser.user }} -p $CASSANDRA_PASSWORD {{ include "common.names.fullname" . }} + +{{ if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }} +Note: Since NetworkPolicy is enabled, only pods with the label below will be able to connect to Cassandra: + + "{{ include "common.names.fullname" . }}-client=true" + +{{- else -}} + +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 {{ include "common.names.namespace" . }} -o jsonpath="{.items[0].status.addresses[0].address}") + export NODE_PORT=$(kubectl get --namespace {{ include "common.names.namespace" . }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "common.names.fullname" . }}) + + cqlsh -u {{ .Values.dbUser.user }} -p $CASSANDRA_PASSWORD $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. + Watch the status with: 'kubectl get svc --namespace {{ include "common.names.namespace" . }} -w {{ include "common.names.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ include "common.names.namespace" . }} {{ include "common.names.fullname" . }} --template "{{ "{{ range (index .status.loadBalancer.ingress 0) }}{{ . }}{{ end }}" }}") + cqlsh -u {{ .Values.dbUser.user }} -p $CASSANDRA_PASSWORD $SERVICE_IP + +{{- else if contains "ClusterIP" .Values.service.type }} + + kubectl port-forward --namespace {{ include "common.names.namespace" . }} svc/{{ include "common.names.fullname" . }} {{ .Values.service.ports.cql }}:{{ .Values.service.ports.cql }} & + cqlsh -u {{ .Values.dbUser.user }} -p $CASSANDRA_PASSWORD 127.0.0.1 {{ .Values.service.ports.cql }} + +{{- end }} +{{- end }} +{{- end }} + +{{- include "common.warnings.rollingTag" .Values.image }} +{{- include "common.warnings.rollingTag" .Values.metrics.image }} +{{- include "common.warnings.rollingTag" .Values.volumePermissions.image }} +{{- include "cassandra.validateValues" . }} +{{- include "common.warnings.resources" (dict "sections" (list "metrics" "" "tls" "volumePermissions") "context" $) }} +{{- include "cassandra.warnings.jvm" . }}{{- include "common.warnings.modifiedImages" (dict "images" (list .Values.image .Values.volumePermissions.image .Values.metrics.image) "context" $) }} +{{- include "common.errors.insecureImages" (dict "images" (list .Values.image .Values.volumePermissions.image .Values.metrics.image) "context" $) }} diff --git a/cassandra/templates/_helpers.tpl b/cassandra/templates/_helpers.tpl new file mode 100644 index 0000000..0d271d9 --- /dev/null +++ b/cassandra/templates/_helpers.tpl @@ -0,0 +1,282 @@ +{{/* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} + +{{/* +Return the proper Cassandra image name +*/}} +{{- define "cassandra.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper metrics image name +*/}} +{{- define "cassandra.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 "cassandra.volumePermissions.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.volumePermissions.image "global" .Values.global) }} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names +*/}} +{{- define "cassandra.imagePullSecrets" -}} +{{ include "common.images.pullSecrets" (dict "images" (list .Values.image .Values.metrics.image .Values.volumePermissions.image) "global" .Values.global) }} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "cassandra.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "common.names.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Return the list of Cassandra seed nodes +*/}} +{{- define "cassandra.seeds" -}} +{{- $seeds := list }} +{{- $fullname := include "common.names.fullname" . }} +{{- $releaseNamespace := include "common.names.namespace" . }} +{{- $clusterDomain := .Values.clusterDomain }} +{{- $seedCount := .Values.cluster.seedCount | int }} +{{- range $e, $i := until $seedCount }} +{{- $seeds = append $seeds (printf "%s-%d.%s-headless.%s.svc.%s" $fullname $i $fullname $releaseNamespace $clusterDomain) }} +{{- end }} +{{- range .Values.cluster.extraSeeds }} +{{- $seeds = append $seeds . }} +{{- end }} +{{- join "," $seeds }} +{{- end -}} + +{{/* +Compile all warnings into a single message, and call fail. +*/}} +{{- define "cassandra.validateValues" -}} +{{- $messages := list -}} +{{- $messages := append $messages (include "cassandra.validateValues.seedCount" .) -}} +{{- $messages := append $messages (include "cassandra.validateValues.tls" .) -}} +{{- $messages := without $messages "" -}} +{{- $message := join "\n" $messages -}} + +{{- if $message -}} +{{- printf "\nVALUES VALIDATION:\n%s" $message | fail -}} +{{- end -}} +{{- end -}} + +{{/* Validate values of Cassandra - Number of seed nodes */}} +{{- define "cassandra.validateValues.seedCount" -}} +{{- $replicaCount := int .Values.replicaCount }} +{{- $seedCount := int .Values.cluster.seedCount }} +{{- if or (lt $seedCount 1) (gt $seedCount $replicaCount) }} +cassandra: cluster.seedCount + + Number of seed nodes must be greater or equal than 1 and less or + equal to `replicaCount`. +{{- end -}} +{{- end -}} + +{{/* Validate values of Cassandra - Tls enabled */}} +{{- define "cassandra.validateValues.tls" -}} +{{- if and (include "cassandra.tlsEncryption" .) (not .Values.tls.autoGenerated) (not .Values.tls.existingSecret) (not .Values.tls.certificatesSecret) }} +cassandra: tls.enabled + In order to enable TLS, you also need to provide + an existing secret containing the Keystore and Truststore or + enable auto-generated certificates. +{{- end -}} +{{- end -}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Return the proper Commit Storage Class +{{ include "cassandra.commitstorage.class" ( dict "persistence" .Values.path.to.the.persistence "global" $) }} +*/}} +{{- define "cassandra.commitstorage.class" -}} +{{- $storageClass := default .persistence.commitStorageClass | default (.global).defaultStorageClass | default "" -}} + +{{- if $storageClass -}} + {{- if (eq "-" $storageClass) -}} + {{- printf "storageClassName: \"\"" -}} + {{- else }} + {{- printf "storageClassName: %s" $storageClass -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if encryption via TLS for client connections should be configured +*/}} +{{- define "cassandra.client.tlsEncryption" -}} +{{- if (or .Values.tls.clientEncryption .Values.cluster.clientEncryption) -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if encryption via TLS for internode communication connections should be configured +*/}} +{{- define "cassandra.internode.tlsEncryption" -}} +{{- if (ne .Values.tls.internodeEncryption "none") -}} + {{- printf "%s" .Values.tls.internodeEncryption -}} +{{- else -}} + {{- printf "none" -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if encryption via TLS should be configured +*/}} +{{- define "cassandra.tlsEncryption" -}} +{{- if or (include "cassandra.client.tlsEncryption" . ) ( ne "none" (include "cassandra.internode.tlsEncryption" . )) -}} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Convert memory to M +Usage: +{{ include "cassandra.memory.convertToM" (dict "value" "3Gi") }} +*/}} +{{- define "cassandra.memory.convertToM" -}} +{{- $res := 0 -}} +{{- if regexMatch "G" .value -}} +{{- /* Multiply by 1000 if it is Gigabytes */ -}} +{{- $res = regexFind "[0-9.]+" .value | float64 | mulf 1000 | int -}} +{{- else -}} +{{- /* Assume M for the rest, so simply extract the number and convert to int */ -}} +{{- $res = regexFind "[0-9]+" .value | int -}} +{{- end -}} +{{- $res -}} +{{- end -}} + +{{/* +Return memory limit if resources or resourcesPreset has been set (in M) +*/}} +{{- define "cassandra.memory.getLimitInM" -}} +{{- $res := "" -}} +{{- if .Values.resources -}} + {{- /* We need to go step by step to avoid nil pointer exceptions */ -}} + {{- if .Values.resources.limits -}} + {{- if .Values.resources.limits.memory -}} + {{- $res = .Values.resources.limits.memory -}} + {{- end -}} + {{- end }} +{{- else if (ne .Values.resourcesPreset "none") -}} + {{- $preset := include "common.resources.preset" (dict "type" .Values.resourcesPreset) | fromYaml -}} + {{- $res = $preset.limits.memory -}} +{{- end -}} +{{- if $res -}} + {{- /* Convert to M */ -}} + {{- include "cassandra.memory.convertToM" (dict "value" $res) -}} +{{- end -}} +{{- end -}} + +{{/* +Calculate Max Heap Size based on the given values +*/}} +{{- define "cassandra.memory.calculateMaxHeapSize" -}} +{{- if .Values.jvm.maxHeapSize -}} +{{- /* Honor value explicitly set */ -}} +{{- print .Values.jvm.maxHeapSize -}} +{{- else -}} +{{- /* Calculate based on resources set */ -}} +{{- /* Reference: https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gc-ergonomics.html */ -}} +{{- $res := include "cassandra.memory.getLimitInM" . -}} +{{- $res = div $res 4 | min 1000 -}} +{{- printf "%vM" $res -}} +{{- end -}} +{{- end -}} + +{{/* +Calculate New Heap Size based on the given values +*/}} +{{- define "cassandra.memory.calculateNewHeapSize" -}} +{{- if .Values.jvm.newHeapSize -}} +{{- /* Honor value explicitly set */ -}} +{{- print .Values.jvm.newHeapSize -}} +{{- else -}} +{{- /* Calculate based on resources set */ -}} +{{- /* Reference: https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gc-ergonomics.html */ -}} +{{- $res := include "cassandra.memory.getLimitInM" . -}} +{{- $res = div $res 64 | max 256 -}} +{{- printf "%vM" $res -}} +{{- end -}} +{{- end -}} + +{{/* +Return the Cassandra TLS credentials secret +*/}} +{{- define "cassandra.tlsSecretName" -}} +{{- $secretName := coalesce .Values.tls.existingSecret .Values.tls.tlsEncryptionSecretName -}} +{{- if $secretName -}} + {{- printf "%s" (tpl $secretName $) -}} +{{- else -}} + {{- printf "%s-crt" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a TLS credentials secret object should be created +*/}} +{{- define "cassandra.createTlsSecret" -}} +{{- if and (include "cassandra.tlsEncryption" .) .Values.tls.autoGenerated (not .Values.tls.existingSecret) (not .Values.tls.tlsEncryptionSecretName) }} + {{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Return true if a TLS credentials secret object should be created +*/}} +{{- define "cassandra.tlsPasswordsSecret" -}} +{{- $secretName := coalesce .Values.tls.passwordsSecret .Values.tls.tlsEncryptionSecretName -}} +{{- if $secretName -}} + {{- printf "%s" (tpl $secretName $) -}} +{{- else -}} + {{- printf "%s-tls-pass" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Get the password to use to access Cassandra +*/}} +{{- define "cassandra.password" -}} + {{- if (and (empty .Values.dbUser.password) .Values.dbUser.forcePassword) }} + {{ required "A Cassandra Password is required!" .Values.dbUser.password }} + {{- else }} + {{- include "common.secrets.passwords.manage" (dict "secret" (include "common.names.fullname" .) "key" "cassandra-password" "providedValues" (list "dbUser.password") "context" $) -}} + {{- end }} +{{- end -}} + +{{/* +Get the metrics config map name. +*/}} +{{- define "cassandra.metricsConfConfigMap" -}} + {{- printf "%s-metrics-conf" (include "common.names.fullname" . ) | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Print warning if jvm memory not set +*/}} +{{- define "cassandra.warnings.jvm" -}} +{{- if not .Values.jvm.maxHeapSize }} +WARNING: JVM Max Heap Size not set in value jvm.maxHeapSize. When not set, the chart will calculate the following size: + MIN(Memory Limit (if set) / 4, 1024M) +{{- end }} +{{- if not .Values.jvm.maxHeapSize }} +WARNING: JVM New Heap Size not set in value jvm.newHeapSize. When not set, the chart will calculate the following size: + MAX(Memory Limit (if set) / 64, 256M) +{{- end }} +{{- end -}} diff --git a/cassandra/templates/cassandra-secret.yaml b/cassandra/templates/cassandra-secret.yaml new file mode 100644 index 0000000..1ad025b --- /dev/null +++ b/cassandra/templates/cassandra-secret.yaml @@ -0,0 +1,39 @@ +{{- /* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if (not .Values.dbUser.existingSecret) -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "common.names.fullname" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +type: Opaque +data: + cassandra-password: {{ include "cassandra.password" . }} +{{ end }} +{{- if and (or .Values.tls.keystorePassword .Values.tls.truststorePassword .Values.tls.autoGenerated) (not .Values.tls.passwordsSecret) (not .Values.tls.tlsEncryptionSecretName) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ printf "%s-tls-pass" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +type: Opaque +data: + {{- if or .Values.tls.keystorePassword .Values.tls.autoGenerated }} + keystore-password: {{ include "common.secrets.passwords.manage" (dict "secret" (printf "%s-%s" (include "common.names.fullname" .) "tls-pass" | trunc 63 | trimSuffix "-") "key" "keystore-password" "providedValues" (list "tls.keystorePassword") "context" $) }} + {{- end }} + {{- if or .Values.tls.truststorePassword .Values.tls.autoGenerated }} + truststore-password: {{ include "common.secrets.passwords.manage" (dict "secret" (printf "%s-%s" (include "common.names.fullname" .) "tls-pass" | trunc 63 | trimSuffix "-") "key" "truststore-password" "providedValues" (list "tls.truststorePassword") "context" $) }} + {{- end }} +{{- end }} diff --git a/cassandra/templates/extra-list.yaml b/cassandra/templates/extra-list.yaml new file mode 100644 index 0000000..329f5c6 --- /dev/null +++ b/cassandra/templates/extra-list.yaml @@ -0,0 +1,9 @@ +{{- /* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- range .Values.extraDeploy }} +--- +{{ include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- end }} diff --git a/cassandra/templates/headless-svc.yaml b/cassandra/templates/headless-svc.yaml new file mode 100644 index 0000000..fb2c555 --- /dev/null +++ b/cassandra/templates/headless-svc.yaml @@ -0,0 +1,33 @@ +{{- /* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +apiVersion: v1 +kind: Service +metadata: + name: {{ printf "%s-headless" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.service.headless.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.service.headless.annotations .Values.commonAnnotations ) "context" . ) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} + {{- end }} +spec: + clusterIP: None + publishNotReadyAddresses: true + ports: + - name: intra + port: 7000 + targetPort: intra + - name: tls + port: 7001 + targetPort: tls + - name: jmx + port: 7199 + targetPort: jmx + - name: cql + port: {{ .Values.service.ports.cql }} + targetPort: cql + {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.podLabels .Values.commonLabels ) "context" . ) }} + selector: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 4 }} diff --git a/cassandra/templates/init_cm.yaml b/cassandra/templates/init_cm.yaml new file mode 100644 index 0000000..ff477b3 --- /dev/null +++ b/cassandra/templates/init_cm.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +binaryData: + init.cql.gz: H4sICIWQC2gAA2Nvd29ya19pbml0LnNxbADtvV2PnDlyJnrfvyIxN1IDNS0y+BVs2wOou9UewT3qRkuzM7M3iVRVSkqrqrJOZVVr5IGB8e7i4Cx8sTj350d4P7w7wNo+f0H9j07Em/kyk8xkSaoifbjNzR7LUn5E8OVDBuOLEV9+/+jhs0eTv3r0u6ffPfzy0eTx15Mn3z6bPPrt46fPnk6uV/PL1eQ3j5/9cnI5vzhdHM+uFsvzyV9M/nDv+HS2Wt2bfD6593RxdnE6f3p1Obuav3x772hyb+e70xez46vlJX9R/e2fffLJl2t+zx5+8c1BZp8Nf35y/5MJvRYnk+3r+eLl4vxq8t33j3/18Pvf8YiPhi/xD6bns7M5/+Nq/vur9dvni+PXB96e/TC7ml1Ory9Po7cvXi3P5yOn7dvzs9nidP/ti+VqMUxE/Pbx5Zym4GQ6u+K3F2fz1dXs7GIzyouTg599SnPy66eP1g9Pf3/4zbNH32+mZ3dCmMbDr76a0KxfTZfnpwsabiBDvxsnNgPkm+Xl69XF7HheFs2b4Nyy/Gz71wPA5nAdsYvn+GS+Or5cXAwDP4wqvztM64eN7WJ2ebU4XlzMzq+i0eWGdbk8nW84M5PHT54++v7Z5PGTZ98efuLJ/cXJ0fAwR7uDP9oZ86ef/JuH3/z60dPJfXl078vlb+i3947uvft/3v3jj3/349+9+8d3//zuv7377/SvP07oL//zx/80efef3/3p3f+g9+kb7/7haPLjH9/9A733Lz/+ux//fvLuT5N3/+XdP//47+lffxx+Td9791/f/cvk3b+8+88//sfhrT8RlR//bvLu/6X3/suPf//j/7X+4o9//+6fJvTLP/Lbw+/+aUKM/oF+9acNcfrSfyBOf3z3T/T2/0n//hMvkldXVxerzx88WNHymH92vPw5z8Bnl9efeyHEA1pc86vVg9Ply+VnF+cv7336/hVLS3s1ezlfr/xDa/aTcXFsFu+Btbv9SmYNhy/siqbffZcby2cvlpdvZpcntI83bw0E7gcyq/n5CUmj7fJer6LtQI5fza6m+6t/+4UN3e130i8sL/mN2el0JJV+4WcvLpdnP9tyWG8I/sunH/aQ/8f18ir7hDvjSxnvPHz60cXs7elydpIdzYEtGoYTFsJ6EHszGDF7fn38en41PV8e/HRvcsOnw8dXby/mk+i1lTB7yEaEL+fH88UPu5/vfnp8upifX02vVlu6NxwOh76woXB9HejzX9efbdfk8fL8ir52w3Jd/2ID8Pj17cSk2G9Ouy14e9NyMp9fTOkwen3gs1ez1fDR9rGfL0l4zs7XH8cfrd9ZXf05//4X62/syN7J/fsb4I+2GH96tIPop5988ulaTnz5za+f0iH6+MlfTr79/is6Tb+gn+9A/9Wjp1/uLL7HT7569NvM4pvuTDz99PeTb5/sL8zJ/Z1vEeEPoRuW0w1Uw3c+dKf8sJi/ObBNMjtg9+1Bh9r/9o5CkyzIDDQ7cByNRD9932Ecxk/0rzLb/IY9fsMG3/1omBxa89frFT/8ZX55q4V2u3X2IUJuShN+zIfUoWnIPWgGyERAremmwO+qrHeE+P3Lfvt0053x5HbA9tuT+ztf/9AZDT+5YVXdeHTcdHDkpjb32bjwbr/qjnb51FyCq+nzt1M+Cauet/z3m47bsE/DK/zsA6aNKX/4lh3GwTO1+5OPmrphG5zREXB4536ApM3I5cyzjtuuulhKxRFZNFujegeueA9EIC+uTrco75jQl3OWyHuG+Ox8cbZW0/mT7fvXZM8vT+Z7dH62JP3mclR3MxMXhv1puo0+cB6Gmc8LkvyOiPTL2enz67NwBEWyYDBCT+eHxMTs+mSxPPyrF4vwk/QjmsWX88O/YsUr86sfFifzDK8flovjDMGDq/TT3S1549rcztjDD1+ZsaJKZ8XpLHdu7mOU/DjZdDdLrdzD7tH88M25P5ysNBp8ReMkJO6H/V072a78aOEfxdvsaNxFR7vb8mi9d4/Grbf1UtyjnXB+QoYFGf4SvDfCSmeUF8ZYafecAfTtl1uXwOnyeHa69grw8l09CKN9EAb1QOL0xYJ++ter5TkzuT3NzQMFiux9IGpf09/5/4vfy68NmHupK+f/z7kEoYyz4LzQJeZSWNodJ9NXc5Ix44TC3Sc0IruZ1e/nJ5Nf8hvrqQVndVszq6QxAGjdHSZgZ2YV+5Lm0zeLq1fTK3ru1Ti/qsD87hMf1y69PfkNvT15xm+Py9gKaGuyjddolZGqiEgQero6Xbx8dXX6dro6W9Ah9nKc7TtskzDbB6hvpvvp5v3J0/X7m/l+YXVj841Og9DSClFEBLvp1avrs+er6fXFONGmgBzeJbuZ4WfDG5NfX4xLWeuvmppaEhvKaI3ClpHIMJ2/JUMrEsl32CRhEUd0N5P7iN7ZFcq0cMVJW7OrlVJCI6oyUtlPZ+cvL98O4nOcXVdgdiO6m9l9yO9MWCKH2QXR1uw6CVbTsefLiGHkWbherF7R4b87w1hghvdob2d5/W4y066tmfZeeiRV2BYRwMJNX13vTbMvMM0x4c0c//L6wAS/aGqCNTipwCJAETEsxfTidD47oTM9mmJ5B/jCMZfS3szyd5s3o3n2btbWPBsjBVr0vohAlnJ6Pr+Ml7EsYdLt0t3M7xN6I55bqdqaW6SjDpzRpoyhDKO6umMtDOd/sEVkAWPvJjajmrz+fLK1TgalI5gn3rV1LtIS986i9FBGXVak1y7OX+8JkwKm4B7toDev30wWfFs2t1HoDSCJ7TtoCDvzrNcrcMWRqzOekcX59AWttDDhBazBPJNdE/zp+OlkcT75mj4N56aSbUFgafJJnEtTRp4b0h9evtxb6SWsw4R00E2G93bX+ddetqX9sbcDhC/mAbXT1cXs8jV9Hia4gIm4S3YU3Jt/jz47wKbm1QI4b71VWMb2NqQ0XF9dzk7jxVvCQExIB5VkeC/WrGVbh6E1wikpAHURIS3k9CXn5HECzXJ5Gia5hI2YkN5M8l+u35t8Se9tHaKP2ppkhzzRXt1FI9uREH56fDq7uGBh+Yp4beVEARtxn/hmor/cvDv5Jb+7ddh93dRUO5bHdN45V0QYg5i+WJ5yHl000XfRHMeJTkmPCsbwXjzJtrVJVto4I63RRSQzyOnVm2VivEABOzEmPOrOb5aJgaJ9W2FAZ4GEBSghishkgCmnur9N1TYoYB7u0R69HZs3Y8XNtWWRc5xVK/C6TFAQNnG7H5Zni6udIBUUMAT3aO+aI/9m82aYZ2jr+EOJyjllfJl4IOi1xHw1e71dywVsv4juaH+Mb2yNj7YCVKitMkrRuVdGFJvpy8vF+fmerChg4u3RHjW4zZuRrLCiLT2ZQ6z0f0raMjLZTk+X1yenb6fHl/uCuYC5d5jBqMpd7slmC22tay8AQGqy/srIZnfAjXm14zyCAmZgnskhT+mbMY9jezy2lVbglZDGGCs+Pn64M/F4yH88O12GiS9gGuaZ5F3U9OlW1rTlUPIGpZLGYpmkA/A7s7J6e/Z8ebqa0mDPltdXrwIMBUzHmxnt5TA9XX9jsjyf/Iq/sVVfvmwLDrTsSVXqLkt1C4cSvFgv9+IFqoBNuUd7u/4v03gBLfumrEonpPLeW+/KBB+VpIW4H5ZRBezKlPRmln+zH5ShSfZtTbKW3hknTJlUBQXT41fz49fPl78PE1zArNwlO+osm3+PzmrRlM3uSEx44Z0TZTIUlCLBOZ++uj4/uZyfhKktYEkmlDez++35fLJ5K3hFHjYmHrxDrVDpMuFEpafPl8uzMLUFDMiR5GZOv6C/byezreUqgXQMjxrKJCMoMu0WL1/upuaqAhbjLtnRWNz8e6ssNGW3OGnUcCHClUkuUHZ6sQy68l38J2FO1xRHP91yuV2ibZ1UEsnWdp7+fxmJ6naV04sFB+s4ZzbMbQEDMMtjV/cd7L6nw4cTTtENmoJqS0QA2X1WkTZWJndA4dpTHOa7gN0XaO56ncf5VNjWegYSDB6F1mXSBJSfns2Gkibzi9np2a7kLWDKHaC+meNfzc4HBXfz9lYO27Zm2xqjQArEInJYi+ny9eAeDldPCphrO1RHPeyvhsjfNrralCnswCsjUEpbJltAy+mL0/nv5yfT5wtaUUEW6wI22h7tUQYPb06+GN7cnn0Pm5pnWrlaA52AZRIGNEwvFufHQ+I37dn59rqaLmCsHaA+yuP125Ov128HWSHaWtVKe+UsaFMmZ0Cr8aLTyfLNeZjpArZbQjm+RPUVvbWVG01FAN0Q/gMwqkzCgCZD63L5en4eX6S6C/EwxQnp0ZYb3pu82rlN9bX2TeXbOi0MoFUSy6QNaLNWZp+fLt+wp2s2fb1YbQVHAfMuw2FXWf5i/dFkNvkr+iioyrKpTEWnlQIQCqFMIoG202N67vPIb6kL2H4x4ZDXRe/EeRrQVBaz01ZKT6aIuIvOtTO9Lo5Db8y1N/PZVpIUMAZvYnMo8r0JivDnW+dxWyahRi+V0MaUSTbQOP2b2Xl8XfMuimWY+V26m6n+t/RGssjXKt+D97/eW7FydbU4fl2rXu5+vcaR3WcvL2cXrxbH09Xib9JqjW8WJ7SatmVx+PVqzvfZt++9p+JKYLP5y5SX2U0FevdLpkY1egLfk8Xq4nT2dl1OaFvQh9bf+aYqUInauh/xZAcf6qbn2p2RtIhMXJco99jRI6b1sHaKT24Y7U9LXC5p95PdVbFDI14uB+b2PdN7pxnm0mKbydrM9U1TOH52GI/3jo3/uVush1/37ycMPz3aYfPeelDhedYFuM6J0+kpcT+0NXYr8UXr6MZltKKfrNaFMNdf/8VhiD6uhOhYZHoc/yDwOFdivopOlcN7fShgvLtsj8Im3TlNtiM82hnM9iCxpPrzXXTgi9IwxF8fDouXLMNHZ8u/Xqx9oB8l9Mfxbp5lFP0bac8sQID5uZA/BzER4vPhf/cyb6dH7J54GOYhWT/pxKwrz+3s1/zxG+3D90zffW3YZSiQHYhasGJyYD7BOX64h09ogT179FWp6XyQMh9P0zsR3zUxEvIhGYse8w/rM+xzI+FofXLxXyd/e/SR0DaNrLGOrwYrqfEwskpjNWR3mVdANiIfwqzYB7JeCSHZJreY27NoayEbMS+PbEw+5PHZLpCVXLRGOlrdqDPIShSVkI2ZF0c2IR8u74kukFVIB5F3xjjh2Vt7aM/6WudszLw4sgn5kPTZxzlLi9l6zYm1RojMnvW+ErIx8+LIJuTDTVDfCbKcKi2lFWAzGpT0UA3ZXeYVkI3IB2ShC2S5XKdDJzTH5cxhaWxqIRszL45sQj7cseoEWbIJyMKzhCfYzDnraunGMfPyyMbkgz3bh25snHLorSQVUsjDexZrmbMx7/LAxuTH0od9WLPGWy+NNGgEcHbZoVNW1LJ5YublgY3Jh0qAfdg8lle0I5lF0spm9Kdqp2zMvDiyCflQrKqPU9ahpmdH4aWWGf1Jy0rAxryLA5uQ30ka7ABXFELS2gb0dBId3rG2liiOeRfHNSE/lsfuQxIjaFrOnEuExsvDWrFVtYCNmJcHNiYfyhyoHpDly8NCWg0euU/K4TNW6zrIJsxLI5uSD5U4dRfIEobWSWsRJGa8TwCmErIx8+LIJuRDzSjTCbIe+O4ZF0Z0hy0eJSsdswnzCshG5MO9+C7OWSuNNUqBl4IvE2eQrXTOJszLIxuTD8j2cc5KFFKSBqk9nUgZW7bWMRvzLg9sTH6n4HUHuIISUllvhBc5SxZUJbdiwrw4sAn5UDGwC78iWXrgHUqlkU6jjCwWtWRxzLw8sjH5UOSnD1mspGV/qnWIALkYT609GzMvjmxCPsR4+tizBCQ6hRYIy4xmXClHJmFdHteY/LZ/WAeoakEYemEF0tAz3uJa5k7MuzisCfmd6/s94Gqtt8ZqmgAnM3asqBTfSZiXBzYmH07YLuI7VnvQZBaQqDI5awegUhZFwrw8sjH54HvqIouCnp6td0KR/sxoxXRQVUN2l3kFZCPyIXe8j1PWKGtQodPsoMnFeGr5i2PmxZFNyIcYTx/+YqON8qQ6Ki79dhhZKWtJ45h5eWRj8qGPYx/S2DilhTfgrPM+FwmoBWzEuzywMfmdArk94OqdIR3DyOH5M3fvarmLY+blgY3Jh7t3ffiLrVUaCUorIHePR0It/SlmXhzZhHxo9NqH/uSUBQIQpfYyY81KV0sYx8yLI5uQD90J+5DGzmmSVAhoJWb8xbIasBHv8sDG5HfaYHeAK4LxpD1qAeBlRi/2tYCNmRcHNiEf7md1gqymR7eolBLZqhSi1ikbMy+PbEw+NH3s45RFrRVqJ9EqzGQYA9byUsTMKyAbkQ/+pz68FF56IYXXHmVOf6rmfop5Fwc2IT/mjneBq6MnN4Zr9AmbvQVtKkXbE+algU3Jh1s8XUTbnUAjpSM8jctlGNdSnxLe5YGNyW+A7UN7clKCBe1ACLLlMzsWKlWkSJgXBzYhH3wUXVSkcLSkkQQVSSvrTMbiEZUiAQnz8sjG5MNd2S4iAQ7oqT04hV6pXB6qq+QxTpgXRzYhH3LauvAYO+6JRyYf4Si9ytzQqnWPJ2FeHNmEfJDGfWjGlrtxoXRs+WUqUkCtxLaEeXFkE/KhE3oXmW3OkaWnlZVSgclFebCWBhUzL45sQj7U4etDg6KnJ9OAzh7wNpclU6umV8K8BrK75EMdvi5yFh0q74zQyngyDDLxu1rAxryLA5uQD8dsH7hqklOOTAMvcxW9lKilGcfMywMbkw9Zxn1oxujJIDDC6MFbk/EsVrqhlTAvj2xMPngWu7ihxdnVNE9aAhdgz3igat29S5iXRjYlH/wUnSCrLCquCOu9yFVrg0pO44R5eWRj8uGY7cJrjMIpT0YBShQ2F5kV1ZCNmJdHNiYfYu59ICut1UbTYQQWMsi6Sm6KhHdxYBPy47XKLrwUKMkw0CCt1yp3w136SpHZhHl5YGPyIf+pi8gsghDeAqJ3NltHplKYJ+FdHNiE/GjydBHloYcnu8BzaNpBxmNcSxDHrCvAGpHfwNqHHGaDwIKzEl2+NlC97brLvAKuEflQHKiT/eq8IyPPWgXZPgG17gQkzMsjG5MPUdk+dGLNFWG1o4XsTO62Ry2vYsK8OLIJ+eCh6MKriMajBq2sBpftAFHrkI15Fwc2IR/M2C5wtVJaNMaRIW8yuU9Qqzh1wrw4sAn5cL+9E2S5wK+nP4zJyWKlKoXuEublkY3Jj+aO6iJ2R9qF8lI4b0lmZWKyuhawMe/iwCbkx8pPfeCKDpwSRnB1yUxOm5KVctoS5sWBTciHwgVd5LQhrWkQWnDwEvxhZE2lxKeEd3FgE/IbYE0XeU/oSZkwjjt1WpfxKEKtzrIJ8/LAxuTDvbsutCcvrBSKrAJP1kEmuqNq3ZVNmJdGNiUf8mO6uCvrJXL3C657hbn77aqSiyLhXRzYhHwoItMFriBRW2QHnMjhCrWyixPmxYFNyAdZ3MUpSwcRiSlDFoElJSNXz6uSwZMwL49sTD7oxV1YPN7SgjacWe20znkVVa1TNmZeHNmEfOgT0McpS9JKgyAkucnU4T0LrpItmzAvj2xMPsR4urBl6em9EyS4QIpc5QKsFJZNeFcANiI/dgzuIirrnR86hxljXO4Oj62lF8e8i+OakB8rjfShFyMtZm5BBApy9wFqlQZKeBfHNSE/7tc+5LAH0iscTYK3Mtd9VFTyPSXMiwObkA8h2T58T95YMeRUA0LmhFWyUgZqwrw8sjH5YO90kYHqeTmT6ugNGMjltLlalmzMvDyyMflQDbUPS9Y7J8jkQ2u9ynkVayUXJ8zLIxuTD9H2HvRiI4RR1pHqKMDmOkDYOsmKKe/CwO6RH/XiHnIV6eHRcK1Qpa3JZY37Ohs25V0e15j8WKetj/0qlUPugy3AuYwktnXCACnv4rgm5Mf92kMUgNs3esXJ1SC0zHgUK4V3Ut7FcU3Ij3ZsH7gqcNLRKeQcZOs9VTtgY+bFgU3IhwzUPk5YpZ1xgiwC77N9eColjafMyyMbkx914i6yxunpucmfFCgk33TJVPKqU4kiZV4e2Zh8qOTVQyUKzs/UwimlBd9PO6w9mTre4pR3eWBj8mOmYg/eYnp4NKQyOqOVxwyuWO2QjXiXxzUmP2pPnZyxXlqjtQThcnmK0lWTxBHz8sDG5INHsQ9JrJU1pGOwFQ+ZmkCmTjw25V0c2IT8KIl7iMfSw2srPNnxpF/kbnlAtSM2Zl4e2Jj8aO90csYaKwWgBdRKZSKyUtRCNmZeHNmEfLj93Auy3CVZG1rXKlO52NQJ26W8KwAbkR9lcQ9RO3p4Lx1oYehveVlcSy2OmZcHNiYfZHEferElawCktNKJnPYkK8VjU+bFkU3Ij7K4k3isk1qgRpoAn+vD42vpxTHv4sAm5Me4XR96MVdCEtw8zNlBYTxYd6+W9hQzLw9sTD7U3etDe3KeWyMYKSWZ9Jm7AHXS2VLe5YGNyYeLWV3g6snYkwKRm9XktKdqKRQx8+LAJuRD14cuzlhazsZ7MF5pzFUYgUpnbMK7NLAp+dCCpw9cDdkE6DgxKGfHQi0PRcK8PLAx+ZAz3sUZKxVaS2qj8tbLTB0vX+ciZcq7OLAJ+VEr7uEepZFacm06WtDK6Nxtu1qSOOZdHNeE/Bi360MSGyEkjZojW7leaFCpUmbKvDiwCfkgiXtBFjRIo9Dk89kq9d9JmVdANiIffIpdRGSlJUNPAdIfnNR3uO5erS0b8y4ObEJ+rLvXx461aNABd+XUmLnhYSqlKSa8y+Makx+jO11kKUouOaicR8t9ajJWrKwFbMy8OLAJ+VESy06QtQ610IZ7hWU8T77SXYCEd3lgY/KjtdPFXQCJCpRRXE5SylxXb1vLPxEzLw5sQn6MAdgu/BMgpHYOSVM0PlfDS/pKsjhhXhrZlHyI7nQhi2nATmlA7rqKGXtH+kr2TsK8PLIx+YBsF/YOCCRZpQlHVDl7B+rt2Yh5eWRj8iG+08eelQpJezSsaIhMPWo6oyohGzMvjmxCPmTH9HHOSkPPTrYeF4DNxNppgmohGzEvj2xMPiDbRbQdhp5h0jmhuF195jZlrT0bMy+ObEI+3KbsY88CSK2k1sqTJpmJBdhaezZmXh7ZmHy4Ad3JnuWrpNwKzqpcLQr6Ry1kI+blkY3Jh77eXWSOA/vJ6dGlU1Lk7lPWUo1j3sWBTciPcdk+NGOlLf9nwHHmV0Z/qrVjY+blgY3JB/2pjx2rJaGolROepitzU7ZSIdSUeXFkE/KhZkEf+pM2aLw1ErnxaiZHphauEevyuMbkR1HcBapGWa+Ekcr7nL0DvtLdrIR5cVwT8sH71MXdLDDekNKorHB5ewcqhe8S5uWRjcmPyEIX8TtwAtEQmoZOoUz8rlbqU8K7OLAJ+TGToo9IgONkTU9iC7KRgFrlnhLe5XGNyY9HbCe4GpJTSBaB8rnuzxIq3eBJmJcHNiYf/BNd3OABniQtUJDymNuxUla6EJAwL45sQn5EVnZxIwA8F+CwFr3P9mmp1Fgp5V0e2Jj8Btgu+ipxZpAnE15rQUdRpjeAqrVjE+algU3Jh64PXexYJRwXbZZa++wdHqjU9SFlXh7ZmHzohdaFT1EpQ3a8UuhIaGX2LEAlxThhXhzZhHywZLvQjPlWGkjJ1WABsxkytZCNmRdHNiEf4gCdIKstAHvKPfhcN9lK+lPCuzywMfnxmO1Df6JnpzPIGqO4LFKmZkE1YCPm5YGNyYeiBZ0g60Bop4WSYDK2rKpVpS1hXh7ZmHzYsl1EAkjFEI7VDNIXs8jqWppxzLw4sgn5EVndh2ZsCUSHNAGcPn/4lLW11KeYd3FgE/JjF54+tCdryJRHKR1Arq4ivV8L2Ih5eWBj8qFjexexO+UsmfJk6pHcylk8tQrJJ7yLA5uQH/2KfexYenjjtKPDCHJ1FVUtt2LMuwauu+THI7YPryIKp6w1DhCdyGWNVypHkTAvDmxCPmSNd1GPQqGiB7cKESXkbnrUOmJj3uWBjcmPO7aPExZRIJCdJwUdRoe9xa5SsD3hXR7XmPx4wnYRa9fCCE3P7cnOy3WSlbU6GCbMSwObkg9VC7rwT9DTO6VIdYRBXmWqtFVSihPmFZCNyIcqbV1oxVqSuQd8r59gzGQ+2UqOp4R3cWAT8qN/ogu/k6b1yz2ltLUih6uSlZSnhHlxYBPyIYuiC+2JazVY4bRCD7ma1NJVuueRMK+AbEQ+dLrr4qaHVgqtdtbQLIic/lQriyJhXhzZhHzIQu3jlFVOeYPWoMn2upO1TJ6EeXlkY/Jhz/Zh83ArXUFQCi995s6dErVsnph5cWQT8uM5K/qweYzyjhUNZ/hMykR4KvkVE+bFkU3IhwhPF35F0iyE1NpyVW6TsWYV1NqzMfPiyCbkQwWZPvYsOq8BAK2leTgcC3CVYjwJ7+LAJuRHz2IXMR7tlVSOK614latGQQZDJWBj5sWBTciHnLZOkHUgnEPpNEImW9HWUoxj3uWBjcmP/qcu9GIjAPkAIqOPzILMjq0Da8K6NKwp+XG/doEqEHYehfdcdj1TCVXUwjVmXhzXhHyIA3SCrBEOtWUHnMzdk9WVfE8J8/LIxuRHD4XuwvdkwEoFzoOlB7OHT1iJlXSnhHl5ZGPyod5TF7oT1y8DSceQUigzVRVrXfRIeJcHNiY/9uHp4p6HUQDeWy46qEymdnEtYyfhXRzXhPyIax/7VSlHtjsYy1ddDuPqKoVkE97lcY3Jj96JLiKyRmvpCEdEDyJTiQKwUkQ2YV4c2IR8aOzdRUTWaKeAtAlvEHNZFFBty8bMyyMbkw8VC/rYs/TUBpUEvnKYQRZrGbIx7+LAJuTHSl592LHGK6vAC1Iesx6KWtfaE+blgY3Jh6hdH1qxBatBOuSraZmoXSVHccK6OK4J+dFR3AeqtKo9GjLylMdcDdRKsdiEeXlcY/KhckwXsVhjETQYlFpwC8fMnfZakjhmXh7ZmHy4096HJCaDwAsNAo1VuX6ytRoFJ8yLI5uQD529u+j6YNB6BM7SBGcyyMpaV+4S5sWRTciHak992DveG6VRC8ctdTOWbLX4Tsy8OLIJ+ZBB0UV8xwoy9LQmcaWVyOXG1OqtlDAvjWxKPmhQXdiyViirPaKXXGoll4Fa6ZxNmJdHNiYfbNkuzlkrrbekPILI13sCrJRbnDAvjmxCPniMu8gtJlMeLLdKxnyMB2wlDSphXhzZhHyoRtGFBmU59ZZTqwnRbN+sWrhGrMvjGpMfNeMuUKX1TBhK4TyXbs5YPJVgjXkXhzUhHwyePnDlms0CpZbZvpRQK8CTMC8PbEw+nLB9aMVaKr6OJo3J932oFGxPeBcHNiE/ZlF0EWu3RlpJq1o4Z6XPVCyohWvMuziuCfnRXdwJrpabmgvhjc91fZC1jNiYd3lcY/LjCduHDWu43wWZel5l84p1tf0a8a6Aa0R+zFLsY79aJ7RHq7kmUqZOZi1HccK7OK4J+RHXPjRix+XL+K5hvl8WmFo+p5h5cWAT8iFq14fPyYEw0rFdYLP5p7qWzylmXh7ZmHyI7fThc0LpLMHorBfZKuOulvIUMy+ObEI+5J/2oT15Kbyy3gD4/I32Wv6JmHlxZBPyYc/24Z/wmivTka5hvc9lx+hKmYoJ8/LIxuQDsl3kKlqPaLSnhW3RZWo91QM24l0e2Jj8qBl3gasTZOuhRqOkFrmOo1BJM06YlwY2JR/qAXWhGTsALdEZ5bkqUq4XWiUnRcK8OLIJ+SCLu/BSONDOamlQGwOZuB2oSvpTwrw8sjH5kBvThf7kNJkEAqQwQsqM/uQr+Z8S3sWBTchvgPVd+J8ctwkDIaQxItsjGGsBGzMvDmxCPkRkO0EWBYCRRstsRepaaYoJ7/LAxuRDCdQucKWnt8ZL6byRmToUspK9k/AujmtCPrTz6ANXbwyC12CUyHVCg0oFRhLm5YGNyQd7p4sKIyiERuE8N+bM1T+tBWzCuzSwKfngLu4EVyv44hIq9Jl88Uo3KRPWFWCNyG9g7eIeJT07Gj9UVmEYD5+vplLcLmFeAdeI/HjAmi7idii0UoYmgIvmZG61y1ptnxPm5ZGNyQfVqQtbB6VA6z1K4yDXFUDV6tGSMC+ObEI+6E6dIIusPEq+v+Qyt+1krY5ZCfPyyMbkxz3bR8csJAteWECvvdQZe0fWuuSRMC+ObEI+INvHngWtrAVlEbJ3n6WvZfDEzMsjG5MfkfV9WDxgUbMpP8CYqYFaC9eIdXlcY/JjqL0PVOkcMgqltpDrvAO1gjsJ8/K4xuRHB0Uf0R3UTtIMCLL5LGZ6F/pKgfaEd3FgE/Jj1K6LODtaDeCFQ0mGQc7ekZXuPSfMiwObkA99ZLu4+YzWodPgnXakOGbyFOshGzEvj2xMfpTFnSDrhFLgNGmO2QwKqWppxTHz4sgm5MOl9j60YqfpGOIrhxJzpyzIWnpxzLw8sjH5sGf70IydJyPees/BrUzdYqVrSeOYeXlkY/KhWmYf0pjMAqtpBrgebCYH1VfKjkl4Fwc2IT9qxl1kxyB6p5S1znE3uMwpW6vCSMK8PLAx+dBXqYsMVPSICg1fTjMyG72rpT/FzIsjm5AP0bsu9CcvDLdH0MKBzlZn05X0p4R5aWRT8uE+QBf6E5nxHLW0pFRw1avD+lMlx2LCuzywMflRferCr+iFF7SkjXIi26dF1rJ4EublgY3Jh9hdJzuWnl5pPo5szv8kZaWstoR5FWR3yAdku8hr8wCD6w1gaGmeqTRSCdiYd3FgE/Kh0EgXuCrp6KGNBuNzeRSqVqXxhHlxYBPyIfepC4vHa+WsElZrVCoTl1XVTtmYeXFkE/IhytPHKas1aEsIGrA+1/fB1VKMY+blkY3JhysBfWjGBjy3CwMYChBmOrZX8hgnzIsjm5APHdu78Bh7bvQHg/5os1ULsBqyEfPyyMbkw03ZPpC13hlw1t1U9alWmkzCvDiyCfmQ/9RFnox3yimJApwTPrdna9WQSZgXRzYhH7rw9KFBeWPlYMm7bN0CWatSW8K8OLIJ+XDO9mH1kMDy3mvgQFfmVqWv5aeIeZcHNiY/RmZ78FOwyojcHgGVpldmx2KdUzZlXhjYPfIhMtvDKcupQSBRWhSGlMhcT9k6kdmUeXFkE/IhS6aHyKwVoIzWyionspULpKy1Z2PmxZFNyIdoQB97VnHrCwdGGJ2rXSB1nQSolHlxZBPyQX/qIQOKnl5LqZTiS8O5DhCyUmuPlHl5ZGPyYc/2gizX9wXntXW5qLutJY1j5hWQjciHDKhOpLHxRnDzeqDHz+TJiGrIRszLIxuTD8XaOkEWDaLW4K3K3nLXdczZlHl5ZGPy4Zztw57VUktgR42WJlOHr05dipR1cVwT8qObog9U6Zm1F/RYmPVSiDp+xZR5eVxj8qExWg9+Ra5nJqwUyDVhVaZPANg6hTNT5sWRTciHHtA9VM60hJ+RpGKQWaDyVcdrIRszL45sQj5UHe8EWaeUG/rCgc9kQJlajsWYd3lgY/JjicU+/IoW6QySyhnCMVcRtdYhG/Muj2tMPoRlO8HVSaeMUgoADuOqVC1rJ2ZeAdiIfLjw0Ye1wx43wcXMhLS5vLZqHoqYeXlkY/JBL+7DQ+EEegta8Y3hTCQAKpWnTpkXRzYhH4RxH6csIjf781IoLjN5ENlKF2ZT3sWBTchvgO3ivqwVXOOXlrYGI7KWrKkli2PmxYFNyIerPH3IYu6QAM6CBaUx433ytSzZmHl5ZGPyoXJmH5asN5whxH06vcrc+HC1LJ6Yd3lgY/IbYF0XFo8UoDUSfoqsvpxe7CrFARLmpYFNyY871nURCZCSFrYXmswCne3yXak+dcq8OLIJ+VDVq4c7WvT02iHJK6fJEMhU4quVRpHwLg9sTH7Ui7vQniQIMuQlIvJfMlkUUAvYmHlxYBPy4SZ0J8iCU1w0VPtsfw9p69zjSZmXRzYmHzKferjHY9lR7rTgeHS2orwSlbIVE+bFkU3Ih8ynLrIVpRZg0Sj00mZrBLlK7qeEeXFkE/JBM+7C/yQ1QeilUWTJmyyylaI8CfPyyMbkA7JdRHmkVorLhpJ54HN375SpJY1j5uWRjcmP0tj0IY0NSLYJnPd8PyIT5amFbMy8OLIJ+RDl6QNZJ4zwliwDK2SuY4Cp5DNOmBdHNiEfogFd+Iyls4rsPs7XdDZXy7iaPRszL49sTH48ZzuxZ8mKF/TgtLR5YWd6QdSyZ2PmxZFNyIdeEH3Ys+suYkMGmM7c5Kl1YTbhXR7YmHy45N4DriA0WE4l8Q5zlWRIs6wDbMK8NLAp+ZD/1EWcByQpjfTkpEW6bLfKWknGCfPiyCbkQ7/vLvwUACyuvKLlnb0XoEQlP0XCvDiyCfngW+zCTwHg2Y7nOs6YzR83taRxzLw8sjH5YPP0IY21FA4cchKYz97SqpQokzAvjmxCPtzS6iJThovCAiJInc9GBV/J5kmYl0c2Jh+qLHZh84ARQoEywtAk5PwUteo/JcyLI5uQD3fc+9CgjEWDzmpUrHBkKntV8honzMsjG5MPlb268BoDGQZkxVvj0avcrQ9ZyWucMC+ObEI+ZLd14TUGrqmvnRIedK6zodS1dOOYeXlkY/JBGvehG9tBWtGattnaFFCptnzKvDyyMfnQJ62HCuQWUBnUnsctc3UWoZYwjnkXBzYhH4yePnA13kkBfAVR5KIBtfIpEublgY3JB99iH/qTB35uwtHRws7lGlcCNuZdHNiEfEg17gRXLZX00jutMlW9XK0jNuZdAdeI/HhPq48T1pPmSDCyrMrW4avUCSJlXh7YmHzIpejC+6QEJxogGXzcaDdTc8RUEsUJ89LIpuRDzmIXslhJRTJLSiTNMVvXq1b+U8K8OLIJ+ZCz2EU2hQKFUilvkDNyM/d5TCVpnDAvjmxCPujFfUhjcI5MeaUdd07ISGOo5H1KmJdHNiYfFOMuvE9KAToBWiiPuY5L9NdKyMbMiyObkB+lsejCS6GUUQBeSCtIaOVq3laK3yXMyyMbkw+5bV3E75SW4IzywimVk8ZQqZt7yrw4sgn5EOXpIgNKaTCO23U6TqTP3Jut5TJOmJdHNiYfztk+pLEx3lmrtTL8+Jn+LZVcUAnz4sgm5EP/li58UAqF0iSrgPtOZTwVIGt5KmLmxZFNyAdp3IenwjslOZFEWpvzGstatysT5sWRTcgH72IXcR4tgCUWkjkvc56KSjWgEtalcU3Jj6dsH6iSfkH/aW9JiczV9qrkWUyYl8c1Jh8kcReeRU1mgfDa00nE9kGmNkUlz2LCvDiyCflQm6ILz6IeLHlhNNl7uQqata65J7zLAxuTH3tBdGHvkLooHCpuiQ1O5bq31MI14l0e15h8aN7SBa7aGi24aTJ3JsrVbKsUCUiYFwc2IR9qtnURCdBGWqe50ZRWMqcT18owTpgXRzYhH24F9IKsR22tMU5gpi6Fr+SgSHhXADYiPzY17MI/oemhvdaSziKJmeynakpxzLs8rjH5MautD53YcrFfNvOc8TndqZKrOOFdHNeEfDBju8DVGe6sa5UlOHMVFqsZOzHz4sAm5EN+TB/WjkMEQxgajybjn1C1Kj8lzMsjG5MPHdL6kMXoleLKoWTs5Sosqlr5MQnz4sgm5EO1kT72rJcEoCP1gibC5qqNVMqPSZgXRzYhH6qNdJEfo71yQgznEa/vTE2KWpZszLw8sjH5UJOiD0vWK5RWA4B3We8T1pLGMfMKyEbkQyG+LqSx4SuH1nipBamPmVh7rSyKhHlpZFPyIT+mCy8FPbFy3NXReYmZ27KqVo3FhHlxZBPyQYPqQhobMCCN5oIrImfPYiUFKuFdHNiE/AZY7EJ/MrR+jUbpvbG5ft9SVXJAJcyLA5uQD3WMu/BAGSWtkIrx9JCJBNRqMZvwLg9sTH6MtneRH2MU30/zILTTMpNFIUW1HRsxLw9sTD7c9ehkx3I3Im21QZvrVymxGrIR8/LIxuSDxdMHsprv9nu+DsHVGzLRgErAxryLA5uQD8GALnA1ypHW6DitWmaqPilVKWs8YV4c2IR8iAV0kTVuDMkrAVpyz86MX5GUkFrIRszLIxuTD7lPfSBrpUXF90kd+Ey3JVnLko15Fwc2IR/Si/vAFZTgS0wCbLa/h63kL06Ylwc2Jh92bB/+YqeNF0hyy/MroxdXirgnzIsjm5APenEXEXfjSLfw2jnpSNnI3IFWtYRxzLw8sjH5oD/1IY3RgNFGySFnM6cZV7oUkDAvjmxCPiDbxa0AgyhJZCmr0OYyjGuljie8ywMbk98A20fmuOV6oaBRCYMyV0++VuwuYV4a2JR8qA7UB7JK00kkOOHACZGp+1QL2Jh3cWAT8iFFpgtcuWWyEOhQGZnLHfeV3IoJ8+LAJuQDsF34Fa3mOr9gpJE6149H6Uq2bMK8PLIx+XA/qwtb1hoQiox4zylgmaw2pSvpxQnz4sgm5AOyXejFlu9DWNTKk2GQvclT65iNmRdHNiEfrvL0cc464MpI0nktdK7WiK3kpUiYF0c2IR+ae3ThpbDOcZ8ppfmCWnbPVkM2Yl4e2Zh82LN9IIsCEQXpjt6KXOXxWnltCfPiyCbkQ1GKLnIprHcgDSA3/8v5jKWpZfXEzIsjm5APyRRdWD1OAOuOaMHabGabrpSymDAvjWxKPvS96yJn0QlnjJD0H51HGQ+UdJWyKRLm5ZGNyYegexfZFE5q6QhNjcJlO3yIWns2Zl4c2YR88Br3sWeldgBSeDAmWyNIVbJnE+YVkI3IhwheF/asUwKFFlZYbX3unDWVdOOEeXFkE/JBg+pCN3ZKEYaaE0o8ZDp8yFr5qAnz8sjG5MNtnj7OWb5Nqp0H8BJzdwN8pRyohHl5ZGPyI7K+ixwox7dKkb00vLoz97SqCeOId3lgY/LjPa1OZDFyH2zBt4WznYNrqU8x7/K4xuTDhu0CV00PZBC95BB15o67qmXxxMyLA5uQD3pxHxYPqYzGC2dRapWJBqhaPuOEeXlkY/IB2T5kMWkXwjiUxnBGSeZuQKWKIwnz8sjG5MPdgC4qjjijOfGLRZbHjGdRyUqZMgnz4sgm5Mc9K7vIlOGnlygM0N9y+hPUyiBPmNdAdpd8iOAVzJS5Edrp87cjoPf3AB7f4L/vIDNZIzO5vw+ENkJrKdhPqjiP4HbrrcKgDE+w1dz+qJlBkTXEwQItLDYzU1KRViBJ/bOs2DcyKLIyBBcPHupDq0YGRdNjPWHnjRlyqRsZFEolpbQCbDML3RiyIchA1KAN3ydoY1AkDLgJNH0CtpU1ZZxy6K2kDShkMzPlrZdGGjRiKEbSxKA4eO4cQUjg2VYWuiM5zo1iPMcLW4EP6ZCh+QL0TjcjpxA0zZHg2TJetjEoK6wZLpB4JDuqEfgs/cs6aS2CxFYkOg3KczV/KQCHPNg2BmWGslFeinVL1jYGhUJK2oCaix61Ah8oLprmSQMVzcgpElDgHWkvpKAPFXSaGBSZ2HzqWS6HD80MygA6hRbo3WZ2nxb0jheWbD9oRnhqa70lTY8G5mQzM+Xp8KNZEs60IxK0Z6FJ/6Y/m9l9RlmDCp1mkd6KlsAX/jl9Uyk/eKPaGBSnHHoDzrqhMEobgyKTnZ1bchhXI4Pim8JIb5KF3IwvwTrFdWklSlITmpFTZF4RbAhISkwzZx+C8bT/tOAckVZ2H9+Hoz+VUqIZnyf77xSyd9kqbMXus8Md/aHxsWxmoTsakTFk0pD20ozTzAk0ckg6Nq4Zu89JCRa0A0EnXysS3dEsIeFG4FlnGhEJDmgwZCMr7rbUiolFepR3JKroHTm0GGxiUJbmh++dssRqxefpnOf0CCulAtOKlsCDIqEAToO3rajDDhVpeaSeG08SoRWJjppgcyQVvGzGue/QkywwwuhBtLcxKDZDPSktEvS6s3cbg1KkTHFojY7kViIOpEMp0jhJUqGwrehTKK3VZJByAgG0MygSChokFyhtxpOHpLN4C4ieDpxWvMM0KBIKnhU9B62cfcgSwZLFLtE1459CDjeQgCLrHZqJIZOFZZAMPqlZ8WxFThlPpx/pLhpcM2cfkiZlkUwZkqCmFR0dLQf6PP1hTDvwcZl9KRxpeLaZ0BoZoGTKCCM4aNSK4TCUrhdasFI1XDhuY1BgheFrEcK6Vo4ZEud0DnNzDuObcQV5OTS+ZPc+NuPJ8yCRu9XTaSMaGpQl1AzJA0tLvRGR4O2QbE6mqNO6lWPGE3QaBL3HCRzNzBTpnIJQBCmacS96OmA4pYROPteML8EjzRCnSQApec3sPg+0wB0NzlvZSqoSNzIUgyEKCM2sKZ4g2n6e+2i2Yjh47xwZfg6t5ZKFTQzKCEHS3NHeE2BbCWzToNBw/Eppa1oxRo2QyiEnwAlwrhn4QHnF9iipn7KRY4Z0c3DScY68g1b86DQo7YwTJBI2DVvaGBTn3fAlFcn+hFYGZbVwSmnBvpdWFrpCQ7vOGTIdsJ1BeWmN1hKEa8Wa4QCINbTUWXq2kiTPV7Gs8CQ/OcuzEbPdCGM5bdgCaqUa0ad4UJxlpum8caqReB8NykuS5WTJ0P+agY8UFrKSpZWumdsgfHNSC9Rkz0jfSl4CDYpOGcHZJc62khFLg/Ic1ybrSpIcbQU+rl5L5zFyckIrC51miJQWMF7pZu440KAMiQR0rKM3I6ekQr6N5dX6nlgjgyJpDnTCcI2LVq78GklGFqktg+LSSloJDwo0GXyk67VjOEhLMkoB0h9s1LQyKDTogFOVNLZitksOzZA1ipbzE1qRU5w4rIU2nFTSjERHBcooDhmt+3K0MCjSzbUjFZ0UPN+Kc58GRWtK0zmD9EcrIgHEcLGW3kHVjEgAOvw4wZMXu2gkCMneOxoSiSgOrLWi5MGQVkLCXKhmEgVpUCC5JggnxcpWDmQAdk9xootVzfg8gc9hGhHZx7KVa0/0b77ix/5qLgXQyprSkv6tlRPet1IYhAZl0HjL17GwlbtYhg4969XQvsS3IxKMN7TxlBWuIZHgyDomFQG41EwzqguXxddkIpNa1c6BzHW0uI06KN9KppkBLgamSX+hDdjOTHn2v1qL3jeTAsDauSfZqbWgVdVIDJkG5TgEyUUc2vElKGVIeCrFObGtlA9jn5QCKTnEBtiKOkyryXIPWe89+FZMLI4T0WqyhlR10cjtWhqUA6GdFtyWtRU5ReucKyV4Ba6hQXFdHodcwQGwFdVFWUPSE6V0ZNe0og4rUjeBRRTB2I5IoEEZp7ljEzQTm+Fr2spa4wDRNXJvhgalaDxWIaKEZhY6khkD3Dq6nRvbhlQW7jdjSSFu5jIPD4rbpVi++UT4NTIoSaIK2LlIb7Sio2sQilM3tLWipUHRcLhKHne6aWT3kY6HVnPlTGFbqVJJg3Jk8JHdx/0yW7GQNad0cV0s4aVvxevC5Yscr3VSXlq5yGq4dD3ZV5bjoqYZOUWanSZVCrmWQysHsvZKcjcdS39pxuepPRkOznEVh2bq5HF2NfJiImG17g/cxKDoiAGPZIxy3LYROcV+RTqOLZ82rRSEpEFZSTafB2uaKeJgONIAkhYUnYGyldiMUQB8+UI4qUwr8T6aIUdSE4xll0Irg9JaOnoPSZ8Srfg86fBTIOmsMYjNaJ6GBmNQcbWZdtRhY7yyCjxXaW5HeFo6i0E6ZNdLK6qLsTRXnuvMSOUbuYdMg0LQYFBq0UyxmaHkvhdkaKHhsliNDIprEwCbWNBMZQleUIaTYYXjxK5GRIIVJKG0Juy0aqVWEA1KkXrO7ZrYT9zIQrfSko6gOfu0HT86yU7S7TQgNqQlWLb42Bqlz5rJ4OBZone4NIjWrfjR6S9c9JQkumwnK8hqqdjdIhu6207nsSRzhhtjuWaukdOgLCflDfczmwls06CclHyXXLVj91nLJRyQewZZ20rAyHLN08Ed1FAGh3UgjHQsGmwzJpZFvoRFJ5/17dxas14KzxWVgCuRNzMozSEQWu/WN3OdwHLhU+1pqmw72YtOkJBCjUbJZjodGgfcW8IZ5RtKaHagHR3KBrVpplKX4WZYZDxIYUQzpchJXyFVGIQg1UU0k9TlLAoAIw1XiW1FR3dc9Nt4KZ03zdxxcDQYgyTNwahWOohx/zcuXus5YamZKBYNyoqhLaRC34oxilwCxw++YX6zlUHxFVbku8iilcK1BqVA0g9QkmxvJoaMdPCxNGBHh2vF64IkOQU3X9Re6mZEAteHtaAsQjtOMwTSplh+Dm80MyhaU9yeQFtoJi9h6OoCKEhW2WauZ5JtzGUXHdJp3ExZHrQO1zUqnW6lIKTh5E4F3O8C2tE8aZpoPbEzSGI7a8p5kpx00LDi0kq8D0kicA8/5CBbKyYW17VXJNOd44yXVtYU6VIKDTte+PJ9G4PiyrCG72uTVdqMNUNykzUpq7hqSSt+dC+80Fx42Il2UgCGQSnNC8s2I9E9wHDGAAxJeY0MSg21zAwZo74ZzdNr5awSVmvkM7CVQWngsn3SgG2l6rfxBjznkwAM8ZlWBkXLCob9Z5txL5KC4IYOoy350ek4doq7/HL54WZmyhsrB9Hp2nEvknbH1WE1d8xr5XI0bznkuDYqTa82ZopVc+CuCdjQ5WgrgI4YrSxpCc24FznwSOg54G5rrbgXaVBaSr6xTQZNK4FtHhTH+chm0M10z+QLWH6oSmfoXG5EHbZcDBlRD80XW9GnrCCDQQILda5E3sbZR4OiwWgytCRgO8KTr6tJwRXNQDUSQ7b0t6H+IskE1UpklAbFBQWHRBfwjejoNChShlEqZ+i9Zo4Zi46MLENCHVq59mS5bSZXFTRGSNvMmiKF01tuQQXYSvKp5ZpKfHNGCsVxo0YGxXE+TrEG7gnQyu7jkDaZWEBWciuJgjQowzo6pys109qFa9trTSeMVLKZCjhWSs7wpGPZGN1K+hsNSjsk9JwGcI2EQawE4bkJHOej+0bSdIdSM4oDWNwKrpHQmuWj2HHVfW7X1Qx8WoBFw4VPbSsuazvUrPVDzQvVSkk69t4pjmBJvoncyoEsDUiWBs63kzvMjS64QwGJBK520cpC54RvEGxiuVZKZ5IVSiOi8dBkNVMYhAY1JJUMtoNuxZcApN5Z1oe9w1a8wxYkbToakORyo61oCVyeC8ErmrB2LGQyGlhwcggSmzFGQUvhwCFbD60Um7EcV+PLfXTctGNicRVdbgXACaitFO+jQQ3dJbizRDMl6cjeEyw1rfHoVStaAnD0WDtFlrJuJQGHBjVAR7Nk2/F5AipDxx+PRDYTmwE0nvt5sjeolTujFjyXbBf0jmum9TAParjKKj1Xt29FTnnaffQWg9dMGEQJVjmRRBXndjWy0JUkjQWkRNp8zagudO6RJsyl8tj6a0ROKTL5SH4qbpaHrfjRlSLlQIAmVRhbSZagQQ3FngSp6pyI2sigNFmhRnnuX9sOfBqM4zwl55qp60Lv0NlnSX9R7ZQmsIpMBq34ogqNqxnh6Z2SrAtLa5s5+7QAhg9JespmhKemcxjpP+1tMxWarSaZILz2yPeRW4kh60F4Cq63ppoJGGku+41D6n4zBSFJQFlDBx/f226mUpfVRlqnOXlDq1a6/PKgPGquCeJEK/dmuN4pbT4taVmR9tnKoCxH+1hEOdNKl1/LBgNpd1Zxw6BW/FMcFwXSp8B4bOXSodU49AsyiuRUM7EZ7SX91dEip/G1klKpPd+YGdZVMx3ueVAo+YomaTDNSHTDXiCu4jDUGG1EdaGBcH1tvnQosRX/lAHu6qnZRdzMXSxrlOCGWJKvFTST/mZINxBS8Se+lTYcNCj2u/ihuVIrZaPtOk1Ck7aAtpmsoKHIjPJ2XSavlUFxP11S09kSla340emA8ZxtJjlhqZVjhquMIjfTta6ZXms0KC5zwYFRsM1E243TxovhEiu/WhkUXwbRjrOaW2mZwC1dgLuWyMHSagU+rpLgBZ0z7dTgsJYDWKBRCYOt9HHgS+20prhkO7hWqula1oRpNOi44n4rxqjVHO7jSmtSN5OXwG2eFMlNzxZEK4aDZYPdkn3Fid/NwOeA/ejSed1MLWt2K3IGh9Lsc2lmplAg4tD427Zyt91y0TBpADkPp5mzzwngnUcKurXNGA7cNtMISf/RumpFonMzclLQDdc6bCbaToNyAFJ4MKYZl7XjMuRaWEG2XyvlLvjKIf1Ls0bsm7nb7tgrRaIcwEtsxUJ27J1Cluc8X60sdMVXo51gl1kzSV1kYZE2xW04hitGrQzK8l0sR1aDbqWmGQ3KeWE49duwStzIoIxmg4Hxa6ai4DAoSaoL0N9uXOifPHjwanZ+cvPgeCSr+8z+ZLG6OJ29nZ7PzuZHk8Xx8nx6fXl6NPnZ8vJkfvmzo8nx5Xwzvmisn4xjNbT/+Nqa5pDf+qLDL4n/Pfr/r66uLlafP3iwulpezon37OX8s+Plz98sL19/dro8np1+7oUQD14sTuerB+MYh9E/uLic/7CYv/ns4vwlUYLM494wCzc9/vrJ91CJp+Lq7cV8+6VhTmbni7PZ1WJvil5ezi5eLY6nq8XfzN83Yfe14Y6xgiPc3FreD3U10xnU/GgPnzz+1cNnj74qM5UPUsabub0L6TAh+8T/erU8J+riaPKHyZvFydWrz0kmHr2aL16+uuK/Tv726CMhbRdRh3zZwJFeavXQQP0AolLUgDThXBbSlHhPkKKWXE9dGS7Wz8rOAUhVDUQTxmURTYn3hKi3nHsluAe8H1K1DyDqaiCaMC6LaEq8I0SNFOiHDlJCKplB1FRANGVcFNE94j0h6jh8px3HPHG4DXMAUaiBaMK4LKIp8Z4Q9WQIKysM3+KTOdWoBqIJ47KIpsQ7QtQO6bkClLIehhp5BxC1FRBNGRdFdI94eUTreQv2Adi3Mf/VXRgHBrVnJrUwqD1Fv4VB7emqDQxqX91qYVB7GkMLg9o79BoY1L7cvsGB+IaOgFfzy389H6LzGul/wLdp10nev1kP4fYSfvMMiScxB8b/kp5EElxWaCFIrK6vRB+Yx+Prq/l0db4cJ+De02cPnz3+sti8PkhHseFzfn1KD6YPnp9aip+QRqS9Edxx3ZPUXl+bOADDu//73T+++x+Td39690/0l39+96efy2qAJOOJAOGMsQOIKOF+QogY1nwU0rI0CoZqegcQqbkn0gHEEMgONgVXyzVaewGSExD8QQguZ4vz5zVRiMcQo3BYtQfUPyUUgAtUGLR8qVllRNPq+vz8bTUMkhHEGKgODGajJF8dFbQSjRiSYw9g8Px09npZDYNkBBEGh7eBAvtTgkAby1dSyaYinZgvDGWEUTUEkgFECPjMifyTOg74Xrfj2xAO3XDj7gACp/zg54vzl/VgiEcRwWB7kEWWK9AJoHlHN9yFPmQxnC6vT6ZvFlevpnQ0VMMiGUp8MBzeElr+pLDgC7FyKHYghqqlOSxWazDOlsuKaMSDidCAw2ig+Smh4ZClg+XscK8yJsObxflJNQSSAcT74bAd/RPbEGiddRoFF29xmTOCN8FGNl3NLq9W1eBIBhPB4To4KoYqiYIVFuDWNYdNh+HErgVBOoIIgh7cGBYQDP9PcxsMcRiCs+X1+VVF1TUdRIQCHrah/U9qI3DRNOORI2pWZzwZx5dvSW+dVnZopEOJsDhsS/+0vEqkvmuUXHHaKLtOEDngz6A5PqsGQTKC+Jje0ZS0ta2Gi/embD+Q8K8fsNof1J5bvYFB7XuWmxhU6mttYVB7rscWBrXni2thUHveqSYGlTpsWhjUnvuiiUGldnwLg9ozZ1sY1J6B18Cg9u2cJgaVav4tDGpPEW5hUHsaYVah+uTB5vXJJ19+/+jhs0eTv3r0u6ffPfzy0eTx15Mn3z6bPPrt46fPnk5IFzxdfTKh128eP/vl5HJ+cbo4HnTXyV9M/nDv+HS2Wt37nHTLxdnF6fzp1SWN8+Vb1uV2vjp9MTsmTfPe5POJ+ts/Cyyf/e67R2sGn10ul2fTi/nl2WK1oh+s7g8s3/9avVlcHb+aEotjUrYvZ5Or+e+vjj76x2eL44/75avZ5Xy6Ig19fj788AN+9+nBB5+fPZ+fnBC0F7NLAnxxMTu/mp6Qfn08/9A52Hmtf0hL5qOeZp8AWy63JfFqQc9zPnm+XJ7OZ+cf9/vdOXr4xTcHF+OwVlaTj5odmpDra/rju+8f/+rh97/jxf5RT0aLfHm8oKV9q6ldnC+u6MfLy1v9evDtTa9Wk6vF2Zz+cXbxUT+fn5/c/sf0i6vr1cePedjObPh+/E9f0GytXk3vNmckbq5np9PL+TGZ1uyMuA2Rs9nvp88vl7OT49nqiqQ24fhxBH5YrBbPT+fTk+vLtRikZft88fJjyeyIxYy0/Chy27Pkloticf7DgnbC6eL89Vr2HZZsuwJt9xE+VqzdScTvE2FRT69bEdmV+iORj6DxQdJtZ9o+fq74NSyOjcC7hfie7OJ2+4Nkcr2aX97lGJnMfpiR5GMP2a1JrE+z1eTpo2d//vX33/7bR0/+/L2n7i9+cRtOtxWUm9clnZW3/vEdD4jN607nxOa1uJjOTk4u56vbz8TF6ezqxfLy7PYE9qRlRhDdalHfVXZuXjt6yOT+ZsMeJTvv0125+vjJV49+OzzP7pJdsQGxXnr0g99Pvn1yQIjcX3/hY4XPdNw8t5FBm9ddRdHmdWetdnwVEm3xsO4k5Davw+shPPeNS+M9ivL01YK9/G9vh2OpGSshXe6+nO6mxo+vMvL2Ljry+Lqbkjy+7nh2xYs3XjBHG+CPRuxo5a4dCV9+8+unzx59//jJX06+/f6rR99PvqAfb1bJV4+efvlBC5zU/MUP8+l6nZMoHPFlXZtm5A6Sa+eVEOVpurUdmX0VkpQ7r230cLtOP0xsDKdMMJ0+2BUTv+hZbniVmcRo+R/kcTu6IxiHX7eHaP6SVaMc5duP9/n18ev5Ve7T29O9mF29yn96e7ocVp5mid+e7kaQZV53orsW+Ifp3ukUGE/GzOuOxIfjJf/prWfkanF1mid8h5kebOspG9rstSmmr/2wOJkvp0MywoFPP9Yhk5BdZzYUJLtjZRx4xdL8fe77V7OrHff994++++bxlw+fPSZL4S8mfwij2/jxJwcc+dvvZBz64Qvs2f/100drnsPV2clLEkuRQ+P527Wtuzgfvpb7Dn82mZ2fDF4EOktWB75INF4sx/cHnpPli+EH45vny6vJ2TXN5EH6Nx6ETC6yoj5ZH4P8QSTAv3j8l4+fPFvPEvPOfjg89u7r2aPfbj5aj3Hn9cW3337z6OGT9afHp/PZ5ajFs6h49vhXj54+e/ir79afr3jH7EqQ5PO91ZR8Hqlv9zcP+OnR+DQHzNB4riJ7dPOjYI3uzePk/kj3zz6Y6DA/N5EcvvARBBmLm+jx5+9TlYafnSxWs+ensR/pfy+Vj9hW02NO2ZxfZidtnJl9bXGfzOTLb3/9hIyKDxzG4vycnnX4BxsPg+S4fxM6B8awS4PE1OQbYvDn62//4n1zuuc3v2GUJPJXs5e3CQlONj/l59ldZLcjsrumPpLMhzztyXx+MQQWPvJB2Um83SQf/JqdLmar4Ycf/rsPeYxh/ZzNz/mo/HjIxtV3W7TOF8ev116pj3uyyfrhdk5UPioXJ/vvDCfryfx0Tgs7/ZQhnDCE6Qc8ovfvyrXCsp60g4ZSbisOD5y+tmviZE665eJiSFw48PFBRXn78U4s4uCvZy+ne/y3Hx+0U3fRjTf5Rj4PomSMWhyQBWOgIuyZXebR78I3frE3F+MqjWMke4t4y2vAPEEkOoK2boedqXjPMXPgO3tHWfSd9+kka4G8GW180q81xfubz25WGtZkeG0cpMEffBCBzfI4TGTz4YcQCkDySsw81uYbnybK+AdtvOn8h/kNCkwUvF47Habny4OfDoSiH4+fbs7ut6fL2S7prW13UMk42vIjfWOk/h5v4jiG0Z+4Ox8Pv6Hvb6bjgLbPA3n41VeT5cXF8pzJjKpTWIK3oBFk+sHfHtYlbzmQDyS2O6KbZ2drSO4SWCs9LDo2Os/7LVI6OhYvNmbkv6ZlesMGiIa0lns/LBcX06vl6/n56madcEedX82HwOLwpd2DZwjiDLTWQix8NMY6p+Pps/erLb/1R/sbZDOso3QI79XFDzx0UPL+l3/u/w/zzvlPOhcEAA== +kind: ConfigMap +metadata: + name: cassandra-init-script + namespace: cassandra diff --git a/cassandra/templates/initdb-configmap.yaml b/cassandra/templates/initdb-configmap.yaml new file mode 100644 index 0000000..53f5817 --- /dev/null +++ b/cassandra/templates/initdb-configmap.yaml @@ -0,0 +1,19 @@ +{{- /* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if and .Values.initDB (not .Values.initDBConfigMap) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-init-scripts" (include "common.names.fullname" .) }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + app.kubernetes.io/part-of: cassandra + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: +{{- include "common.tplvalues.render" (dict "value" .Values.initDB "context" .) | nindent 2 }} +{{ end }} diff --git a/cassandra/templates/metrics-configmap.yaml b/cassandra/templates/metrics-configmap.yaml new file mode 100644 index 0000000..d999d2f --- /dev/null +++ b/cassandra/templates/metrics-configmap.yaml @@ -0,0 +1,19 @@ +{{- /* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-metrics-conf" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + app.kubernetes.io/part-of: cassandra + app.kubernetes.io/component: cassandra-exporter + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: + config.yml: |- + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.configuration "context" $) | nindent 4 }} diff --git a/cassandra/templates/networkpolicy.yaml b/cassandra/templates/networkpolicy.yaml new file mode 100644 index 0000000..894474d --- /dev/null +++ b/cassandra/templates/networkpolicy.yaml @@ -0,0 +1,82 @@ +{{- /* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if .Values.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: {{ include "common.capabilities.networkPolicy.apiVersion" . }} +metadata: + name: {{ include "common.names.fullname" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.podLabels .Values.commonLabels ) "context" . ) }} + podSelector: + matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} + policyTypes: + - Ingress + - Egress + {{- if .Values.networkPolicy.allowExternalEgress }} + egress: + - {} + {{- else }} + egress: + # Allow dns resolution + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + # Allow connection to other cluster pods + - ports: + - port: {{ .Values.containerPorts.cql }} + - port: {{ .Values.containerPorts.jmx }} + - port: {{ .Values.containerPorts.tls }} + - port: {{ .Values.containerPorts.intra }} + to: + - podSelector: + matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 14 }} + {{- if .Values.networkPolicy.extraEgress }} + {{- include "common.tplvalues.render" ( dict "value" .Values.rts.networkPolicy.extraEgress "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} + ingress: + - ports: + - port: {{ .Values.containerPorts.cql }} + - port: {{ .Values.containerPorts.jmx }} + - port: {{ .Values.containerPorts.tls }} + - port: {{ .Values.containerPorts.intra }} + {{- if .Values.metrics.enabled }} + - port: {{ .Values.metrics.containerPorts.http }} + - port: {{ .Values.metrics.containerPorts.jmx }} + {{- end }} + {{- if not .Values.networkPolicy.allowExternal }} + from: + - podSelector: + matchLabels: + {{ template "common.names.fullname" . }}-client: "true" + - podSelector: + matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 14 }} + {{- if .Values.networkPolicy.ingressNSMatchLabels }} + - namespaceSelector: + matchLabels: + {{- range $key, $value := .Values.networkPolicy.ingressNSMatchLabels }} + {{ $key | quote }}: {{ $value | quote }} + {{- end }} + {{- if .Values.networkPolicy.ingressNSPodMatchLabels }} + podSelector: + matchLabels: + {{- range $key, $value := .Values.networkPolicy.ingressNSPodMatchLabels }} + {{ $key | quote }}: {{ $value | quote }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.networkPolicy.extraIngress }} + {{- include "common.tplvalues.render" ( dict "value" .Values.networkPolicy.extraIngress "context" $ ) | nindent 4 }} + {{- end }} +{{- end }} diff --git a/cassandra/templates/pdb.yaml b/cassandra/templates/pdb.yaml new file mode 100644 index 0000000..e34aa45 --- /dev/null +++ b/cassandra/templates/pdb.yaml @@ -0,0 +1,26 @@ +{{- /* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if .Values.pdb.create }} +apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ include "common.names.fullname" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- 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 or .Values.pdb.maxUnavailable ( not .Values.pdb.minAvailable ) }} + maxUnavailable: {{ .Values.pdb.maxUnavailable | default 1 }} + {{- end }} + {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.podLabels .Values.commonLabels ) "context" . ) }} + selector: + matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} +{{- end }} diff --git a/cassandra/templates/service.yaml b/cassandra/templates/service.yaml new file mode 100644 index 0000000..d2f5bc6 --- /dev/null +++ b/cassandra/templates/service.yaml @@ -0,0 +1,59 @@ +{{- /* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +apiVersion: v1 +kind: Service +metadata: + name: {{ include "common.names.fullname" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.service.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.service.annotations .Values.commonAnnotations ) "context" . ) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + {{- if and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerIP)) }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + {{- if and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerSourceRanges)) }} + loadBalancerSourceRanges: {{- toYaml .Values.service.loadBalancerSourceRanges | nindent 4 }} + {{- end }} + {{- if and .Values.service.clusterIP (eq .Values.service.type "ClusterIP") }} + clusterIP: {{ .Values.service.clusterIP }} + {{- 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: cql + port: {{ .Values.service.ports.cql }} + targetPort: cql + {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.cql)) }} + nodePort: {{ .Values.service.nodePorts.cql }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + {{- if .Values.metrics.enabled }} + - name: metrics + port: {{ .Values.service.ports.metrics }} + targetPort: metrics + {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.metrics)) }} + nodePort: {{ .Values.service.nodePorts.metrics }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + {{- end }} + {{- if .Values.service.extraPorts }} + {{- include "common.tplvalues.render" (dict "value" .Values.service.extraPorts "context" $) | nindent 4 }} + {{- end }} + {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.podLabels .Values.commonLabels ) "context" . ) }} + selector: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 4 }} diff --git a/cassandra/templates/serviceaccount.yaml b/cassandra/templates/serviceaccount.yaml new file mode 100644 index 0000000..9ae54f5 --- /dev/null +++ b/cassandra/templates/serviceaccount.yaml @@ -0,0 +1,18 @@ +{{- /* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "cassandra.serviceAccountName" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.serviceAccount.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.serviceAccount.annotations .Values.commonAnnotations ) "context" . ) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} +{{- end }} diff --git a/cassandra/templates/servicemonitor.yaml b/cassandra/templates/servicemonitor.yaml new file mode 100644 index 0000000..0c12f54 --- /dev/null +++ b/cassandra/templates/servicemonitor.yaml @@ -0,0 +1,46 @@ +{{- /* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- 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 | quote }} + {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.metrics.serviceMonitor.labels .Values.commonLabels ) "context" . ) }} + labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} + {{- 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" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 6 }} + {{- if .Values.metrics.serviceMonitor.selector }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.serviceMonitor.selector "context" $) | nindent 6 }} + {{- end }} + 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: {{- toYaml .Values.metrics.serviceMonitor.metricRelabelings | nindent 6 }} + {{- 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" . }} +{{- end }} diff --git a/cassandra/templates/statefulset.yaml b/cassandra/templates/statefulset.yaml new file mode 100644 index 0000000..7b9b7b2 --- /dev/null +++ b/cassandra/templates/statefulset.yaml @@ -0,0 +1,690 @@ +{{- /* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ include "common.names.fullname" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.podLabels .Values.commonLabels ) "context" . ) }} + selector: + matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} + serviceName: {{ printf "%s-headless" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }} + podManagementPolicy: {{ .Values.podManagementPolicy }} + replicas: {{ .Values.replicaCount }} + updateStrategy: {{- include "common.tplvalues.render" (dict "value" .Values.updateStrategy "context" $ ) | nindent 4 }} + template: + metadata: + labels: {{- include "common.labels.standard" ( dict "customLabels" $podLabels "context" $ ) | nindent 8 }} + {{- if or .Values.podAnnotations (and .Values.metrics.enabled .Values.metrics.podAnnotations) }} + annotations: + {{- if .Values.podAnnotations }} + {{- toYaml .Values.podAnnotations | nindent 8 }} + {{- end }} + {{- if .Values.metrics.podAnnotations }} + {{- toYaml .Values.metrics.podAnnotations | nindent 8 }} + {{- end }} + {{- end }} + spec: + {{- include "cassandra.imagePullSecrets" . | nindent 6 }} + automountServiceAccountToken: {{ .Values.automountServiceAccountToken }} + {{- if .Values.hostAliases }} + hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.hostAliases "context" $) | nindent 8 }} + {{- end }} + serviceAccountName: {{ template "cassandra.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 "customLabels" $podLabels "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset "customLabels" $podLabels "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.schedulerName }} + schedulerName: {{ .Values.schedulerName | quote }} + {{- end }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName | quote }} + {{- end }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.podSecurityContext "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 or .Values.initContainers (include "cassandra.tlsEncryption" . ) (and .Values.podSecurityContext.enabled .Values.volumePermissions.enabled .Values.persistence.enabled) }} + initContainers: + {{- if and .Values.podSecurityContext.enabled .Values.volumePermissions.enabled .Values.persistence.enabled }} + - name: volume-permissions + image: {{ include "cassandra.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} + {{- else }} + command: + - /bin/sh + - -cx + - | + {{- if .Values.persistence.enabled }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown `id -u`:`id -G | cut -d " " -f2` {{ .Values.persistence.mountPath }} + {{- else }} + chown {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} {{ .Values.persistence.mountPath }} + {{- end }} + mkdir -p {{ .Values.persistence.mountPath }}/data + chmod 700 {{ .Values.persistence.mountPath }}/data + find {{ .Values.persistence.mountPath }} -mindepth 1 -maxdepth 1 -not -name ".snapshot" -not -name "lost+found" | \ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + xargs chown -R `id -u`:`id -G | cut -d " " -f2` + {{- else }} + xargs chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} + {{- end }} + {{- end }} + {{- if .Values.persistence.commitLogMountPath }} + - /bin/sh + - -cx + - | + {{- if .Values.persistence.enabled }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + chown `id -u`:`id -G | cut -d " " -f2` {{ .Values.persistence.mountPath }} + {{- else }} + chown {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} {{ .Values.persistence.mountPath }} + {{- end }} + mkdir -p {{ .Values.persistence.commitLogMountPath }}/commitlog + chmod 700 {{ .Values.persistence.commitLogMountPath }}/commitlog + find {{ .Values.persistence.mountPath }} -mindepth 1 -maxdepth 1 -not -name ".snapshot" -not -name "lost+found" | \ + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + xargs -r chown -R `id -u`:`id -G | cut -d " " -f2` + {{- else }} + xargs -r chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- 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 }} + {{- else if ne .Values.volumePermissions.resourcesPreset "none" }} + resources: {{- include "common.resources.preset" (dict "type" .Values.volumePermissions.resourcesPreset) | nindent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: {{ .Values.persistence.mountPath }} + - name: empty-dir + mountPath: /tmp + subPath: tmp-dir + {{- if .Values.persistence.commitLogMountPath }} + - name: commitlog + mountPath: {{ .Values.persistence.commitLogMountPath }} + {{- end }} + {{- end }} + {{- if (include "cassandra.tlsEncryption" . ) }} + - name: init-certs + image: {{ include "cassandra.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy | quote }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.containerSecurityContext "context" $) | nindent 12 }} + {{- end }} + command: + - /bin/bash + - -ec + - |- + {{- if .Values.tls.autoGenerated }} + if [[ -f "/certs/tls.key" ]] && [[ -f "/certs/tls.crt" ]] && [[ -f "/certs/ca.crt" ]]; then + openssl pkcs12 -export -in "/certs/tls.crt" \ + -passout pass:"${CASSANDRA_KEYSTORE_PASSWORD}" \ + -inkey "/certs/tls.key" \ + -out "/tmp/keystore.p12" + keytool -importkeystore -srckeystore "/tmp/keystore.p12" \ + -srcstoretype PKCS12 \ + -srcstorepass "${CASSANDRA_KEYSTORE_PASSWORD}" \ + -deststorepass "${CASSANDRA_KEYSTORE_PASSWORD}" \ + -destkeystore "/opt/bitnami/cassandra/certs/keystore" \ + -noprompt + rm "/tmp/keystore.p12" + keytool -import -file "/certs/ca.crt" \ + -keystore "/opt/bitnami/cassandra/certs/truststore" \ + -storepass "${CASSANDRA_TRUSTSTORE_PASSWORD}" \ + -noprompt + else + echo "Couldn't find the expected PEM certificates! They are mandatory when encryption via TLS is enabled." + exit 1 + fi + {{- else }} + if [[ -f "/certs/truststore" ]] && [[ -f "/certs/keystore" ]]; then + cp "/certs/truststore" "/opt/bitnami/cassandra/certs/truststore" + cp "/certs/keystore" "/opt/bitnami/cassandra/certs/keystore" + else + echo "Couldn't find the expected Java Key Stores (JKS) files! They are mandatory when encryption via TLS is enabled." + exit 1 + fi + {{- end }} + env: + - name: MY_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + {{- if or .Values.tls.passwordsSecret .Values.tls.tlsEncryptionSecretName .Values.tls.truststorePassword .Values.tls.autoGenerated }} + {{- if .Values.usePasswordFiles }} + - name: CASSANDRA_TRUSTSTORE_PASSWORD_FILE + value: "/opt/bitnami/cassandra/secrets/truststore-password" + {{- else }} + - name: CASSANDRA_TRUSTSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "cassandra.tlsPasswordsSecret" . }} + key: truststore-password + {{- end }} + {{- end }} + {{- if or .Values.tls.passwordsSecret .Values.tls.tlsEncryptionSecretName .Values.tls.keystorePassword .Values.tls.autoGenerated }} + {{- if .Values.usePasswordFiles }} + - name: CASSANDRA_KEYSTORE_PASSWORD_FILE + value: "/opt/bitnami/cassandra/secrets/keystore-password" + {{- else }} + - name: CASSANDRA_KEYSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "cassandra.tlsPasswordsSecret" . }} + key: keystore-password + {{- end }} + {{- end }} + {{- if .Values.tls.resources }} + resources: {{- toYaml .Values.tls.resources | nindent 12 }} + {{- else if ne .Values.tls.resourcesPreset "none" }} + resources: {{- include "common.resources.preset" (dict "type" .Values.tls.resourcesPreset) | nindent 12 }} + {{- end }} + volumeMounts: + - name: script-volume + mountPath: /scripts + - name: certs + mountPath: /certs + - name: certs-shared + mountPath: /opt/bitnami/cassandra/certs + - name: empty-dir + mountPath: /tmp + subPath: tmp-dir + {{- if .Values.usePasswordFiles }} + - name: cassandra-secrets + mountPath: /opt/bitnami/cassandra/secrets + {{- end }} + {{- end }} + {{- if .Values.initContainers }} + {{- include "common.tplvalues.render" (dict "value" .Values.initContainers "context" $) | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.hostNetwork }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + {{- end }} + containers: + - name: cassandra + command: + {{- if .Values.command }} + {{- include "common.tplvalues.render" (dict "value" .Values.command "context" $) | nindent 12 }} + {{- else }} + - bash + - -ec + - | + # Node 0 is the password seeder + if [[ $POD_NAME =~ (.*)-0$ ]]; then + echo "Setting node as password seeder" + export CASSANDRA_PASSWORD_SEEDER=yes + else + # Only node 0 will execute the startup initdb scripts + export CASSANDRA_IGNORE_INITDB_SCRIPTS=1 + fi + /opt/bitnami/scripts/cassandra/entrypoint.sh /opt/bitnami/scripts/cassandra/run.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 }} + image: {{ include "cassandra.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy | quote }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.containerSecurityContext "context" $) | nindent 12 }} + {{- end }} + env: + - name: BITNAMI_DEBUG + value: {{ ternary "true" "false" (or .Values.image.debug .Values.diagnosticMode.enabled) | quote }} + - name: CASSANDRA_CLUSTER_NAME + value: {{ .Values.cluster.name }} + - name: CASSANDRA_SEEDS + value: {{ (include "cassandra.seeds" .) | quote }} + {{- if .Values.usePasswordFiles }} + - name: CASSANDRA_PASSWORD_FILE + value: {{ printf "/opt/bitnami/cassandra/secrets/%s" (include "common.secrets.key" (dict "existingSecret" .Values.dbUser.existingSecret "key" "cassandra-password")) }} + {{- else }} + - name: CASSANDRA_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "common.secrets.name" (dict "existingSecret" .Values.dbUser.existingSecret "context" $) }} + key: {{ include "common.secrets.key" (dict "existingSecret" .Values.dbUser.existingSecret "key" "cassandra-password") }} + {{- end }} + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: CASSANDRA_USER + value: {{ .Values.dbUser.user | quote }} + - name: CASSANDRA_NUM_TOKENS + value: {{ .Values.cluster.numTokens | quote }} + - name: CASSANDRA_DATACENTER + value: {{ .Values.cluster.datacenter }} + - name: CASSANDRA_ENDPOINT_SNITCH + value: {{ .Values.cluster.endpointSnitch }} + - name: CASSANDRA_KEYSTORE_LOCATION + value: "/opt/bitnami/cassandra/certs/keystore" + - name: CASSANDRA_TRUSTSTORE_LOCATION + value: "/opt/bitnami/cassandra/certs/truststore" + {{- if ne "none" (include "cassandra.internode.tlsEncryption" .) }} + - name: CASSANDRA_INTERNODE_ENCRYPTION + value: {{ (include "cassandra.internode.tlsEncryption" .) | quote }} + {{- end }} + {{- if (include "cassandra.client.tlsEncryption" .) }} + - name: CASSANDRA_CLIENT_ENCRYPTION + value: "true" + {{- end }} + {{- if or .Values.tls.passwordsSecret .Values.tls.tlsEncryptionSecretName .Values.tls.truststorePassword .Values.tls.autoGenerated }} + {{- if .Values.usePasswordFiles }} + - name: CASSANDRA_TRUSTSTORE_PASSWORD_FILE + value: "/opt/bitnami/cassandra/secrets/truststore-password" + {{- else }} + - name: CASSANDRA_TRUSTSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "cassandra.tlsPasswordsSecret" . }} + key: truststore-password + {{- end }} + {{- end }} + {{- if or .Values.tls.passwordsSecret .Values.tls.tlsEncryptionSecretName .Values.tls.keystorePassword .Values.tls.autoGenerated }} + {{- if .Values.usePasswordFiles }} + - name: CASSANDRA_KEYSTORE_PASSWORD_FILE + value: "/opt/bitnami/cassandra/secrets/keystore-password" + {{- else }} + - name: CASSANDRA_KEYSTORE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "cassandra.tlsPasswordsSecret" . }} + key: keystore-password + {{- end }} + {{- end }} + - name: CASSANDRA_RACK + value: {{ .Values.cluster.rack }} + {{- if or .Values.jvm.maxHeapSize (include "cassandra.memory.getLimitInM" .) }} + - name: MAX_HEAP_SIZE + value: {{ include "cassandra.memory.calculateMaxHeapSize" . | quote }} + {{- end }} + {{- if or .Values.jvm.newHeapSize (include "cassandra.memory.getLimitInM" .) }} + - name: HEAP_NEWSIZE + value: {{ include "cassandra.memory.calculateNewHeapSize" . | quote }} + {{- end }} + {{- if .Values.jvm.extraOpts }} + - name: JVM_EXTRA_OPTS + value: {{ .Values.jvm.extraOpts | quote }} + {{- end }} + {{- if .Values.cluster.enableUDF }} + - name: CASSANDRA_ENABLE_USER_DEFINED_FUNCTIONS + value: {{ .Values.cluster.enableUDF | quote }} + {{- end }} + {{- if .Values.containerPorts.intra }} + - name: CASSANDRA_TRANSPORT_PORT_NUMBER + value: {{ .Values.containerPorts.intra | quote }} + {{- end }} + {{- if .Values.containerPorts.jmx }} + - name: CASSANDRA_JMX_PORT_NUMBER + value: {{ .Values.containerPorts.jmx | quote }} + {{- end }} + {{- if .Values.containerPorts.cql }} + - name: CASSANDRA_CQL_PORT_NUMBER + value: {{ .Values.containerPorts.cql | quote }} + {{- end }} + {{- if .Values.persistence.commitLogMountPath }} + - name: CASSANDRA_COMMITLOG_DIR + value: {{ .Values.persistence.commitLogMountPath | quote }} + {{- end }} + {{- if .Values.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + 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 }} + {{- 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: + exec: + command: + - /bin/bash + - -ec + - | + nodetool info | grep "Native Transport active: true" + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 12 }} + {{- else if .Values.readinessProbe.enabled }} + readinessProbe: + exec: + command: + - /bin/bash + - -ec + - | + nodetool status | grep -E "^UN\\s+${POD_IP}" + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + {{- end }} + {{- if .Values.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.startupProbe.enabled }} + startupProbe: + exec: + command: + - /bin/bash + - -ec + - | + nodetool status | grep -E "^UN\\s+${POD_IP}" + initialDelaySeconds: {{ .Values.startupProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.startupProbe.periodSeconds }} + timeoutSeconds: {{ .Values.startupProbe.timeoutSeconds }} + successThreshold: {{ .Values.startupProbe.successThreshold }} + failureThreshold: {{ .Values.startupProbe.failureThreshold }} + {{- end }} + {{- if not .Values.lifecycleHooks }} + lifecycle: + postStart: + exec: + command: + - /bin/bash + - -c + - set -euo pipefail + - mkdir -p /tmp/scripts + - cp /scripts/init.cql.gz /tmp/scripts/ + - cd /tmp/scripts && gzip -d init.cql.gz + until cqlsh -u cassandra -p "$(cat /opt/bitnami/cassandra/secrets/cassandra-password)" -e "DESCRIBE KEYSPACES" | grep -q 'system_schema'; do + echo "Waiting for Cassandra to fully start..." + sleep 5 + done + - cqlsh -u cassandra -p "$(cat /opt/bitnami/cassandra/secrets/cassandra-password)" -f /tmp/scripts/init.cql + preStop: + exec: + command: + - bash + - -ec + {{- if not .Values.persistence.enabled }} + - nodetool decommission + {{- else }} + - nodetool drain + {{- end }} + {{- else if .Values.lifecycleHooks }} + lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.lifecycleHooks "context" $) | nindent 12 }} + {{- end }} + {{- end }} + ports: + - name: intra + containerPort: {{ .Values.containerPorts.intra | default "7000" }} + {{- if .Values.hostNetwork }} + hostPort: {{ .Values.containerPorts.intra }} + {{- else if .Values.hostPorts.intra }} + hostPort: {{ .Values.hostPorts.intra }} + {{- end }} + {{- if (ne (include "cassandra.internode.tlsEncryption" .) "none") }} + - name: tls + containerPort: {{ .Values.containerPorts.tls | default "7001" }} + {{- if .Values.hostNetwork }} + hostPort: {{ .Values.containerPorts.tls }} + {{- else if .Values.hostPorts.tls }} + hostPort: {{ .Values.hostPorts.tls }} + {{- end }} + {{- end }} + - name: jmx + containerPort: {{ .Values.containerPorts.jmx | default "7199" }} + {{- if .Values.hostNetwork }} + hostPort: {{ .Values.containerPorts.jmx }} + {{- else if .Values.hostPorts.jmx }} + hostPort: {{ .Values.hostPorts.jmx }} + {{- end }} + - name: cql + containerPort: {{ .Values.containerPorts.cql | default "9042" }} + {{- if .Values.hostNetwork }} + hostPort: {{ .Values.containerPorts.cql }} + {{- else if .Values.hostPorts.cql }} + hostPort: {{ .Values.hostPorts.cql }} + {{- end }} + {{- if .Values.resources }} + resources: {{ toYaml .Values.resources | nindent 12 }} + {{- else if ne .Values.resourcesPreset "none" }} + resources: {{- include "common.resources.preset" (dict "type" .Values.resourcesPreset) | nindent 12 }} + {{- end }} + volumeMounts: + - name: script-volume + mountPath: /scripts + - name: data + mountPath: {{ .Values.persistence.mountPath }} + {{- if .Values.usePasswordFiles }} + - name: cassandra-secrets + mountPath: /opt/bitnami/cassandra/secrets + {{- end }} + {{- if .Values.persistence.commitLogMountPath }} + - name: commitlog + mountPath: {{ .Values.persistence.commitLogMountPath }} + {{- end }} + {{- if (include "cassandra.tlsEncryption" . ) }} + - name: certs-shared + mountPath: /opt/bitnami/cassandra/certs + {{- end }} + {{- if or .Values.initDBConfigMap .Values.initDB }} + - name: init-db-cm + mountPath: /docker-entrypoint-initdb.d/configmap + {{- end }} + {{- if .Values.initDBSecret }} + - name: init-db-secret + mountPath: /docker-entrypoint-initdb.d/secret + {{- end }} + {{ if .Values.existingConfiguration }} + - name: configurations + mountPath: {{ .Values.persistence.mountPath }}/conf + {{- end }} + - name: empty-dir + mountPath: /tmp + subPath: tmp-dir + - name: empty-dir + mountPath: /opt/bitnami/cassandra/conf + subPath: app-conf-dir + - name: empty-dir + mountPath: /opt/bitnami/cassandra/tmp + subPath: app-tmp-dir + - name: empty-dir + mountPath: /opt/bitnami/cassandra/logs + subPath: app-logs-dir + {{- if .Values.extraVolumeMounts }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraVolumeMounts "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.metrics.enabled }} + - name: metrics + image: {{ include "cassandra.metrics.image" . }} + imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} + {{- 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 }} + {{- end }} + ports: + - name: metrics + containerPort: {{ .Values.metrics.containerPorts.http | default "8080" }} + {{- if .Values.hostNetwork }} + hostPort: {{ .Values.metrics.containerPorts.http }} + {{- else if .Values.metrics.hostPorts.http }} + hostPort: {{ .Values.metrics.hostPorts.http }} + {{- end }} + protocol: TCP + - name: jmx + containerPort: {{ .Values.metrics.containerPorts.jmx | default "5555" }} + {{- if .Values.hostNetwork }} + hostPort: {{ .Values.metrics.containerPorts.jmx }} + {{- else if .Values.metrics.hostPorts.jmx }} + hostPort: {{ .Values.metrics.hostPorts.jmx }} + {{- end }} + {{- if .Values.metrics.resources }} + resources: {{- toYaml .Values.metrics.resources | nindent 12 }} + {{- else if ne .Values.metrics.resourcesPreset "none" }} + resources: {{- include "common.resources.preset" (dict "type" .Values.metrics.resourcesPreset) | nindent 12 }} + {{- end }} + {{- if not .Values.diagnosticMode.enabled }} + livenessProbe: + tcpSocket: + port: metrics + 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 }} + volumeMounts: + - name: metrics-conf + mountPath: /opt/bitnami/cassandra-exporter/config.yml + subPath: config.yml + - name: empty-dir + mountPath: /tmp + subPath: tmp-dir + {{- if .Values.metrics.extraVolumeMounts }} + {{- include "common.tplvalues.render" (dict "value" .Values.metrics.extraVolumeMounts "context" $) | nindent 12 }} + {{- end }} + {{- end }} + {{- if .Values.sidecars }} + {{- include "common.tplvalues.render" (dict "value" .Values.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + - name: script-volume + configMap: + name: cassandra-init-script + - name: metrics-conf + configMap: + name: {{ include "cassandra.metricsConfConfigMap" . }} + {{- if .Values.usePasswordFiles }} + - name: cassandra-secrets + projected: + sources: + - secret: + name: {{ include "common.secrets.name" (dict "existingSecret" .Values.dbUser.existingSecret "context" $) }} + {{- if or .Values.tls.passwordsSecret .Values.tls.tlsEncryptionSecretName .Values.tls.keystorePassword .Values.tls.truststorePassword .Values.tls.autoGenerated }} + - secret: + name: {{ include "cassandra.tlsPasswordsSecret" . }} + {{- end }} + {{- end }} + {{- if (include "cassandra.tlsEncryption" . ) }} + - name: certs + secret: + secretName: {{ include "cassandra.tlsSecretName" . }} + defaultMode: 256 + - name: certs-shared + emptyDir: + sizeLimit: 500Mi + {{- end }} + {{- if .Values.existingConfiguration }} + - name: configurations + configMap: + name: {{ tpl .Values.existingConfiguration $ }} + {{- end }} + - name: empty-dir + emptyDir: {} + {{- if or .Values.initDB .Values.initDBConfigMap }} + - name: init-db-cm + configMap: + name: {{ ternary (printf "%s-init-scripts" (include "common.names.fullname" .)) (tpl .Values.initDBConfigMap $) (empty .Values.initDBConfigMap) }} + {{- end }} + {{- if .Values.initDBSecret }} + - name: init-db-secret + secret: + secretName: {{ tpl .Values.initDBSecret $ }} + {{- end }} + {{- if .Values.extraVolumes }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraVolumes "context" $) | nindent 8 }} + {{- end }} + {{- if and .Values.persistence.enabled .Values.persistence.existingClaim }} + - name: data + persistentVolumeClaim: + claimName: {{ tpl .Values.persistence.existingClaim $ }} + {{- else if not .Values.persistence.enabled }} + - name: data + emptyDir: {} + {{- else }} + volumeClaimTemplates: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: data + labels: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 10 }} + {{- if .Values.persistence.annotations }} + annotations: {{- toYaml .Values.persistence.annotations | 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.commitLogMountPath }} + - metadata: + name: commitlog + labels: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 10 }} + {{- if .Values.persistence.annotations }} + annotations: {{- toYaml .Values.persistence.annotations | nindent 10 }} + {{- end }} + spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.commitLogsize | quote }} + {{- include "cassandra.commitstorage.class" (dict "persistence" .Values.persistence "global" .Values.global) | nindent 8 }} + {{- end }} + {{- end }} diff --git a/cassandra/templates/tls-secret.yaml b/cassandra/templates/tls-secret.yaml new file mode 100644 index 0000000..6b1c3ad --- /dev/null +++ b/cassandra/templates/tls-secret.yaml @@ -0,0 +1,30 @@ +{{- /* +Copyright Broadcom, Inc. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if (include "cassandra.createTlsSecret" . ) }} +{{- $secretName := printf "%s-crt" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }} +{{- $ca := genCA "cassandra-ca" 365 }} +{{- $fullname := include "common.names.fullname" . }} +{{- $releaseNamespace := include "common.names.namespace" . }} +{{- $clusterDomain := .Values.clusterDomain }} +{{- $serviceName := include "common.names.fullname" . }} +{{- $headlessServiceName := printf "%s-headless" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }} +{{- $altNames := list (printf "*.%s.%s.svc.%s" $serviceName $releaseNamespace $clusterDomain) (printf "%s.%s.svc.%s" $serviceName $releaseNamespace $clusterDomain) (printf "*.%s.%s.svc.%s" $headlessServiceName $releaseNamespace $clusterDomain) (printf "%s.%s.svc.%s" $headlessServiceName $releaseNamespace $clusterDomain) "localhost" "127.0.0.1" $fullname }} +{{- $cert := genSignedCert $fullname nil $altNames 365 $ca }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ $secretName }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +type: kubernetes.io/tls +data: + tls.crt: {{ include "common.secrets.lookup" (dict "secret" $secretName "key" "tls.crt" "defaultValue" $cert.Cert "context" $) }} + tls.key: {{ include "common.secrets.lookup" (dict "secret" $secretName "key" "tls.key" "defaultValue" $cert.Key "context" $) }} + ca.crt: {{ include "common.secrets.lookup" (dict "secret" $secretName "key" "ca.crt" "defaultValue" $ca.Cert "context" $) }} +{{- end }} diff --git a/cassandra/values.yaml b/cassandra/values.yaml new file mode 100644 index 0000000..45c78f9 --- /dev/null +++ b/cassandra/values.yaml @@ -0,0 +1,972 @@ +# Copyright Broadcom, Inc. All Rights Reserved. +# SPDX-License-Identifier: APACHE-2.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 +## @param global.defaultStorageClass Global default StorageClass for Persistent Volume(s) +## +global: + imageRegistry: "" + ## E.g. + ## imagePullSecrets: + ## - myRegistryKeySecretName + ## + imagePullSecrets: [] + defaultStorageClass: "" + ## Security parameters + ## + security: + ## @param global.security.allowInsecureImages Allows skipping image verification + allowInsecureImages: false + ## Compatibility adaptations for Kubernetes platforms + ## + compatibility: + ## Compatibility adaptations for Openshift + ## + openshift: + ## @param global.compatibility.openshift.adaptSecurityContext Adapt the securityContext sections of the deployment to make them compatible with Openshift restricted-v2 SCC: remove runAsUser, runAsGroup and fsGroup and let the platform use their allowed default IDs. Possible values: auto (apply if the detected running cluster is Openshift), force (perform the adaptation always), disabled (do not perform adaptation) + ## + adaptSecurityContext: auto +## @section Common parameters +## + +## @param nameOverride String to partially override common.names.fullname +## +nameOverride: "" +## @param fullnameOverride String to fully override common.names.fullname +## +fullnameOverride: "" +## @param kubeVersion Force target Kubernetes version (using Helm capabilities if not set) +## +kubeVersion: "" +## @param commonLabels Labels to add to all deployed objects (sub-charts are not considered) +## +commonLabels: {} +## @param commonAnnotations Annotations to add to all deployed objects +## +commonAnnotations: {} +## @param clusterDomain Kubernetes cluster domain name +## +clusterDomain: cluster.local +## @param extraDeploy Array of extra objects to deploy with the release +## +extraDeploy: [] +## @param usePasswordFiles Mount credentials as files instead of using environment variables +## +usePasswordFiles: true +## 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 Cassandra parameters +## + +## Bitnami Cassandra image +## ref: https://hub.docker.com/r/bitnami/cassandra/tags/ +## @param image.registry [default: REGISTRY_NAME] Cassandra image registry +## @param image.repository [default: REPOSITORY_NAME/cassandra] Cassandra image repository +## @skip image.tag Cassandra image tag (immutable tags are recommended) +## @param image.digest Cassandra image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag +## @param image.pullPolicy image pull policy +## @param image.pullSecrets Cassandra image pull secrets +## @param image.debug Enable image debug mode +## +image: + registry: docker.io + repository: bitnami/cassandra + tag: 5.0.3-debian-12-r6 + digest: "" + ## Specify a imagePullPolicy + ## ref: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-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: [] + ## Enable debug mode + ## + debug: false +## Secret with keystore, keystore password, truststore, truststore password +## DEPRECATED. Use tls.existingSecret instead +# tlsEncryptionSecretName: + +## Database credentials +## @param dbUser.user Cassandra admin user +## @param dbUser.forcePassword Force the user to provide a non +## @param dbUser.password Password for `dbUser.user`. Randomly generated if empty +## @param dbUser.existingSecret Use an existing secret object for `dbUser.user` password (will ignore `dbUser.password`) +## +dbUser: + user: cassandra + forcePassword: false + password: "tnQ5jUwRv2I" + ## Use an existing secrets which already stores your password data. + ## for backwards compatibility, existingSecret can be a simple string, + ## referencing the secret by name. + ## existingSecret: + ## ## Name of the existing secret + ## ## + ## name: mySecret + ## ## Key mapping where is the value which the deployment is expecting and + ## ## is the name of the key in the existing secret. + ## ## + ## keyMapping: + ## cassandra-password: myCassandraPasswordKey + ## + existingSecret: "" + existingSecretPasswordKey: "" +## @param initDB Object with cql scripts. Useful for creating a keyspace and pre-populating data +## +initDB: {} +## @param initDBConfigMap ConfigMap with cql scripts. Useful for creating a keyspace and pre-populating data +## +initDBConfigMap: {} + +## @param initDBSecret Secret with cql script (with sensitive data). Useful for creating a keyspace and pre-populating data +## +initDBSecret: "" +## @param existingConfiguration ConfigMap with custom cassandra configuration files. This overrides any other Cassandra configuration set in the chart +## +existingConfiguration: "" +## Cluster parameters +## @param cluster.name Cassandra cluster name +## @param cluster.seedCount Number of seed nodes +## @param cluster.numTokens Number of tokens for each node +## @param cluster.datacenter Datacenter name +## @param cluster.rack Rack name +## @param cluster.endpointSnitch Endpoint Snitch +## @param cluster.clientEncryption Client Encryption +## @param cluster.extraSeeds For an external/second cassandra ring. +## @param cluster.enableUDF Enable User defined functions +## +cluster: + name: cassandra + seedCount: 1 + numTokens: 256 + datacenter: dc1 + rack: rack1 + endpointSnitch: SimpleSnitch + clientEncryption: false + ## eg: + ## extraSeeds: + ## - hostname/IP + ## - hostname/IP + ## + extraSeeds: [] + enableUDF: false +## JVM Settings +## @param jvm.extraOpts Set the value for Java Virtual Machine extra options +## @param jvm.maxHeapSize Set Java Virtual Machine maximum heap size (MAX_HEAP_SIZE). Calculated automatically if `nil` +## @param jvm.newHeapSize Set Java Virtual Machine new heap size (HEAP_NEWSIZE). Calculated automatically if `nil` +## +jvm: + extraOpts: "" + ## Memory settings: These are calculated automatically unless specified otherwise + ## To run on environments with little resources (<= 8GB), tune your heap settings: + ## - calculate 1/2 ram and cap to 1024MB + ## - calculate 1/4 ram and cap to 8192MB + ## - pick the max + ## + maxHeapSize: "" + ## newHeapSize: + ## A good guideline is 100 MB per CPU core. + ## - min(100 * num_cores, 1/4 * heap size) + ## ref: https://docs.datastax.com/en/archived/cassandra/2.0/cassandra/operations/ops_tune_jvm_c.html + ## + newHeapSize: "" +## @param command Command for running the container (set to default if not set). Use array form +## +command: [] +## @param args Args for running the container (set to default if not set). Use array form +## +args: [] +## @param extraEnvVars Extra environment variables to be set on cassandra container +## For example: +## - 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 +## +extraEnvVarsSecret: "" +## @section Statefulset parameters +## + +## @param replicaCount Number of Cassandra replicas +## +replicaCount: 1 +## @param updateStrategy.type updateStrategy for Cassandra statefulset +## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies +## +updateStrategy: + type: RollingUpdate +## @param automountServiceAccountToken Mount Service Account token in pod +## +automountServiceAccountToken: false +## @param hostAliases Add deployment host aliases +## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ +## +hostAliases: [] +## @param podManagementPolicy StatefulSet pod management policy +## +podManagementPolicy: OrderedReady +## @param priorityClassName Cassandra pods' priority. +## ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ +## +priorityClassName: "" +## @param podAnnotations Additional pod annotations +## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ +## +podAnnotations: {} +## @param podLabels Additional pod labels +## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ +## +podLabels: {} +## @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 + ## + 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/concepts/scheduling-eviction/assign-pod-node/ +## +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 +## https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ +## The value is evaluated as a template +## +topologySpreadConstraints: [] +## Pod security context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod +## @param podSecurityContext.enabled Enabled Cassandra pods' Security Context +## @param podSecurityContext.fsGroupChangePolicy Set filesystem group change policy +## @param podSecurityContext.sysctls Set kernel settings using the sysctl interface +## @param podSecurityContext.supplementalGroups Set filesystem extra groups +## @param podSecurityContext.fsGroup Set Cassandra pod's Security Context fsGroup +## +podSecurityContext: + enabled: true + fsGroupChangePolicy: Always + sysctls: [] + supplementalGroups: [] + fsGroup: 1001 +## Configure Container 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 Enabled Cassandra containers' Security Context +## @param containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in container +## @param containerSecurityContext.runAsUser Set Cassandra containers' Security Context runAsUser +## @param containerSecurityContext.runAsGroup Set Cassandra containers' Security Context runAsGroup +## @param containerSecurityContext.allowPrivilegeEscalation Set Cassandra containers' Security Context allowPrivilegeEscalation +## @param containerSecurityContext.capabilities.drop Set Cassandra containers' Security Context capabilities to be dropped +## @param containerSecurityContext.readOnlyRootFilesystem Set Cassandra containers' Security Context readOnlyRootFilesystem +## @param containerSecurityContext.runAsNonRoot Set Cassandra containers' Security Context runAsNonRoot +## @param containerSecurityContext.privileged Set container's Security Context privileged +## @param containerSecurityContext.seccompProfile.type Set container's Security Context seccomp profile +## +containerSecurityContext: + enabled: true + seLinuxOptions: {} + runAsUser: 1001 + runAsGroup: 1001 + runAsNonRoot: true + privileged: false + allowPrivilegeEscalation: false + capabilities: + drop: ["ALL"] + seccompProfile: + type: "RuntimeDefault" + readOnlyRootFilesystem: true +## Cassandra pods' resource requests and limits +## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ +## Minimum memory for development is 4GB and 2 CPU cores +## Minimum memory for production is 8GB and 4 CPU cores +## ref: http://docs.datastax.com/en/archived/cassandra/2.0/cassandra/architecture/architecturePlanningHardware_c.html +## +## 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 resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if resources is set (resources is recommended for production). +## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 +## +resourcesPreset: "large" +## @param resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) +## Example: +## resources: +## requests: +## cpu: 2 +## memory: 512Mi +## limits: +## cpu: 3 +## memory: 1024Mi +## +resources: {} +## Configure extra options for Cassandra containers' liveness and readiness probes +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-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: 60 + periodSeconds: 30 + timeoutSeconds: 30 + successThreshold: 1 + failureThreshold: 5 +## @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: 60 + periodSeconds: 10 + timeoutSeconds: 30 + successThreshold: 1 + failureThreshold: 5 +## Configure extra options for startup probe +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-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: 0 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 60 +## @param customLivenessProbe Custom livenessProbe that overrides the default one +## +customLivenessProbe: {} +## @param customReadinessProbe Custom readinessProbe that overrides the default one +## +customReadinessProbe: {} +## @param customStartupProbe [object] Override default startup probe +## +customStartupProbe: {} +## @param lifecycleHooks [object] Override default etcd container hooks +## +lifecycleHooks: {} +## @param schedulerName Alternative scheduler +## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ +## +schedulerName: "" +## @param terminationGracePeriodSeconds In seconds, time the given to the Cassandra pod needs to terminate gracefully +## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods +## +terminationGracePeriodSeconds: "" +## @param extraVolumes Optionally specify extra list of additional volumes for cassandra container +## +extraVolumes: [] +## @param extraVolumeMounts Optionally specify extra list of additional volumeMounts for cassandra container +## +extraVolumeMounts: [] +## @param initContainers Add additional init containers to the cassandra pods +## +initContainers: [] +## @param sidecars Add additional sidecar containers to the cassandra pods +## +sidecars: [] +## Cassandra 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 + ## + create: true + ## @param pdb.minAvailable Mininimum number of pods that must still be available after the eviction + ## + minAvailable: "" + ## @param pdb.maxUnavailable Max number of pods that can be unavailable after the eviction + ## + maxUnavailable: "" +## @param hostNetwork Enable HOST Network +## If hostNetwork true -> dnsPolicy is set to ClusterFirstWithHostNet +## +hostNetwork: false +## Cassandra container ports to open +## If hostNetwork true: the hostPort is set identical to the containerPort +## @param containerPorts.intra Intra Port on the Host and Container +## @param containerPorts.tls TLS Port on the Host and Container +## @param containerPorts.jmx JMX Port on the Host and Container +## @param containerPorts.cql CQL Port on the Host and Container +## +containerPorts: + intra: 7000 + tls: 7001 + jmx: 7199 + cql: 9042 +## Cassandra ports to be exposed as hostPort +## If hostNetwork is false, only the ports specified here will be exposed (or not if set to an empty string) +## @param hostPorts.intra Intra Port on the Host +## @param hostPorts.tls TLS Port on the Host +## @param hostPorts.jmx JMX Port on the Host +## @param hostPorts.cql CQL Port on the Host +## +hostPorts: + intra: "" + tls: "" + jmx: "" + cql: "" +## @section RBAC parameters +## + +## Cassandra 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 Cassandra pods + ## + create: true + ## @param serviceAccount.name The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the cassandra.fullname template + ## + name: "" + ## @param serviceAccount.annotations Annotations for Cassandra Service Account + ## + annotations: {} + ## @param serviceAccount.automountServiceAccountToken Automount API credentials for a service account. + ## + automountServiceAccountToken: false +## @section Traffic Exposure Parameters +## + +## Cassandra service parameters +## +service: + ## @param service.type Cassandra service type + ## + type: ClusterIP + ## @param service.ports.cql Cassandra service CQL Port + ## @param service.ports.metrics Cassandra service metrics port + ## + ports: + cql: 9042 + metrics: 8080 + ## Node ports to expose + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## @param service.nodePorts.cql Node port for CQL + ## @param service.nodePorts.metrics Node port for metrics + ## + nodePorts: + cql: "" + metrics: "" + ## @param service.extraPorts Extra ports to expose in the service (normally used with the `sidecar` value) + ## + extraPorts: [] + ## @param service.loadBalancerIP LoadBalancerIP if service type is `LoadBalancer` + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer + ## + loadBalancerIP: "" + ## @param service.loadBalancerSourceRanges 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.clusterIP Service Cluster IP + ## e.g.: + ## clusterIP: None + ## + clusterIP: "" + ## @param service.externalTrafficPolicy 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 Provide any additional annotations which may be required. + ## 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.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 service.sessionAffinityConfig Additional settings for the sessionAffinity + ## sessionAffinityConfig: + ## clientIP: + ## timeoutSeconds: 300 + ## + sessionAffinityConfig: {} + ## Headless service properties + ## + headless: + ## @param service.headless.annotations Annotations for the headless service. + ## + 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: true + ## @param networkPolicy.allowExternal Don't require server label for connections + ## The Policy model to apply. When set to false, only pods with the correct + ## server label will have network access to the ports server is listening + ## on. When true, server will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + ## @param networkPolicy.allowExternalEgress Allow the pod to access any range of port and all destinations. + ## + allowExternalEgress: true + ## @param networkPolicy.extraIngress [array] Add extra ingress rules to the NetworkPolicy + ## e.g: + ## extraIngress: + ## - ports: + ## - port: 1234 + ## from: + ## - podSelector: + ## - matchLabels: + ## - role: frontend + ## - podSelector: + ## - matchExpressions: + ## - key: role + ## operator: In + ## values: + ## - frontend + extraIngress: [] + ## @param networkPolicy.extraEgress [array] Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true) + ## e.g: + ## extraEgress: + ## - ports: + ## - port: 1234 + ## to: + ## - podSelector: + ## - matchLabels: + ## - role: frontend + ## - podSelector: + ## - matchExpressions: + ## - key: role + ## operator: In + ## values: + ## - frontend + ## + extraEgress: [] + ## @param networkPolicy.ingressNSMatchLabels [object] Labels to match to allow traffic from other namespaces + ## @param networkPolicy.ingressNSPodMatchLabels [object] Pod labels to match to allow traffic from other namespaces + ## + ingressNSMatchLabels: {} + ingressNSPodMatchLabels: {} +## @section Persistence parameters +## + +## Enable persistence using Persistent Volume Claims +## ref: https://kubernetes.io/docs/concepts/storage/persistent-volumes/ +## +persistence: + ## @param persistence.enabled Enable Cassandra data persistence using PVC, use a Persistent Volume Claim, If false, use emptyDir + ## + enabled: true + ## @param persistence.existingClaim Name of an existing PVC to use + ## + existingClaim: "" + ## @param persistence.storageClass PVC Storage Class for Cassandra 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.commitStorageClass PVC Storage Class for Cassandra Commit Log volume + ## Storage class to use with CASSANDRA_COMMITLOG_DIR to reduce the concurrence for writing data and commit logs + ## ref: https://github.com/bitnami/containers/tree/main/bitnami/cassandra + ## If set to "-", commitStorageClass: "", 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) + ## + commitStorageClass: "" + ## @param persistence.annotations Persistent Volume Claim annotations + ## + annotations: {} + ## @param persistence.accessModes Persistent Volume Access Mode + ## + accessModes: + - ReadWriteOnce + ## @param persistence.size PVC Storage Request for Cassandra data volume + ## + size: 8Gi + ## @param persistence.commitLogsize PVC Storage Request for Cassandra commit log volume. Unset by default + ## + commitLogsize: 2Gi + ## @param persistence.mountPath The path the data volume will be mounted at + ## + mountPath: /bitnami/cassandra + ## @param persistence.commitLogMountPath The path the commit log volume will be mounted at. Unset by default. Set it to '/bitnami/cassandra/commitlog' to enable a separate commit log volume + ## + # commitLogMountPath: /bitnami/cassandra/commitlog + commitLogMountPath: "" +## @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 + ## + enabled: false + ## @param volumePermissions.image.registry [default: REGISTRY_NAME] Init container volume image registry + ## @param volumePermissions.image.repository [default: REPOSITORY_NAME/os-shell] Init container volume image repository + ## @skip volumePermissions.image.tag Init container volume image tag (immutable tags are recommended) + ## @param volumePermissions.image.digest Init container volume image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag + ## @param volumePermissions.image.pullPolicy Init container volume pull policy + ## @param volumePermissions.image.pullSecrets Specify docker-registry secret names as an array + ## + image: + registry: docker.io + repository: bitnami/os-shell + tag: 12-debian-12-r39 + 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: [] + ## Init container' resource requests and limits + ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + ## 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.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if volumePermissions.resources is set (volumePermissions.resources is recommended for production). + ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 + ## + resourcesPreset: "nano" + ## @param volumePermissions.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) + ## Example: + ## resources: + ## requests: + ## cpu: 2 + ## memory: 512Mi + ## limits: + ## cpu: 3 + ## memory: 1024Mi + ## + resources: {} + ## Init container Security Context + ## Note: the chown of the data folder is done to securityContext.runAsUser + ## and not the below volumePermissions.securityContext.runAsUser + ## @param volumePermissions.securityContext.seLinuxOptions [object,nullable] Set SELinux options in container + ## @param volumePermissions.securityContext.runAsUser User ID for the init container + ## + ## 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 + ## pod securityContext.enabled=false and shmVolume.chmod.enabled=false + ## + securityContext: + seLinuxOptions: {} + runAsUser: 0 +## @section Metrics parameters +## + +## Cassandra Prometheus exporter configuration +## +metrics: + ## @param metrics.enabled Start a side-car prometheus exporter + ## + enabled: false + ## Bitnami Cassandra Exporter image + ## ref: https://hub.docker.com/r/bitnami/cassandra-exporter/tags/ + ## @param metrics.image.registry [default: REGISTRY_NAME] Cassandra exporter image registry + ## @param metrics.image.repository [default: REPOSITORY_NAME/cassandra-exporter] Cassandra exporter image name + ## @skip metrics.image.tag Cassandra exporter image tag + ## @param metrics.image.digest Cassandra exporter image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag + ## @param metrics.image.pullPolicy image pull policy + ## @param metrics.image.pullSecrets Specify docker-registry secret names as an array + ## + image: + registry: docker.io + repository: bitnami/cassandra-exporter + tag: 2.3.8-debian-12-r41 + 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: [] + ## Cassandra Prometheus exporter resource requests and limits + ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + ## 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.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if metrics.resources is set (metrics.resources is recommended for production). + ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 + ## + resourcesPreset: "nano" + ## @param metrics.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) + ## Example: + ## resources: + ## requests: + ## cpu: 2 + ## memory: 512Mi + ## limits: + ## cpu: 3 + ## memory: 1024Mi + ## + resources: {} + ## @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: + initialDelaySeconds: 20 + periodSeconds: 10 + timeoutSeconds: 45 + failureThreshold: 3 + successThreshold: 1 + ## @param metrics.extraVolumeMounts Optionally specify extra list of additional volumeMounts for cassandra-exporter container + ## + extraVolumeMounts: [] + ## @param metrics.podAnnotations [object] Metrics exporter pod Annotation and Labels + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + podAnnotations: + prometheus.io/scrape: "true" + prometheus.io/port: "8080" + ## Prometheus Operator ServiceMonitor configuration + ## + serviceMonitor: + ## @param metrics.serviceMonitor.enabled If `true`, creates a Prometheus Operator ServiceMonitor (also requires `metrics.enabled` to be `true`) + ## + enabled: false + ## @param metrics.serviceMonitor.namespace Namespace in which Prometheus is running + ## + namespace: monitoring + ## @param metrics.serviceMonitor.interval Interval at which metrics should be scraped. + ## ref: https://github.com/coreos/prometheus-operator/blob/main/Documentation/api.md#endpoint + ## e.g: + ## interval: 10s + ## + interval: "" + ## @param metrics.serviceMonitor.scrapeTimeout Timeout after which the scrape is ended + ## ref: https://github.com/coreos/prometheus-operator/blob/main/Documentation/api.md#endpoint + ## e.g: + ## scrapeTimeout: 10s + ## + scrapeTimeout: "" + ## @param metrics.serviceMonitor.selector Prometheus instance selector labels + ## ref: https://github.com/bitnami/charts/tree/main/bitnami/prometheus-operator#prometheus-configuration + ## e.g: + ## selector: + ## prometheus: my-prometheus + ## + selector: {} + ## @param metrics.serviceMonitor.metricRelabelings Specify Metric Relabelings to add to the scrape endpoint + ## ref: https://github.com/coreos/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + ## @param metrics.serviceMonitor.relabelings RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/coreos/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + ## @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: "" + ## @param metrics.serviceMonitor.labels Used to pass Labels that are required by the installed Prometheus Operator + ## ref: https://github.com/coreos/prometheus-operator/blob/main/Documentation/api.md#prometheusspec + ## + labels: {} + ## Metrics container ports to open + ## If hostNetwork true: the hostPort is set identical to the containerPort + ## @param metrics.containerPorts.http HTTP Port on the Host and Container + ## @param metrics.containerPorts.jmx JMX Port on the Host and Container + ## + containerPorts: + http: 8080 + jmx: 5555 + ## Metrics ports to be exposed as hostPort + ## If hostNetwork is false, only the ports specified here will be exposed (or not if set to an empty string) + ## @param metrics.hostPorts.http HTTP Port on the Host + ## @param metrics.hostPorts.jmx JMX Port on the Host + ## + hostPorts: + http: "" + jmx: "" + ## @param metrics.configuration [string] Configure Cassandra-exporter with a custom config.yml file + ## ref: https://github.com/criteo/cassandra_exporter/blob/main/config.yml + ## + configuration: | + host: localhost:{{ .Values.containerPorts.jmx }} + ssl: False + user: + password: + listenPort: {{ .Values.metrics.containerPorts.http }} + blacklist: + # To profile the duration of jmx call you can start the program with the following options + # > java -Dorg.slf4j.simpleLogger.defaultLogLevel=trace -jar cassandra_exporter.jar config.yml --oneshot + # + # To get intuition of what is done by cassandra when something is called you can look in cassandra + # https://github.com/apache/cassandra/tree/trunk/src/java/org/apache/cassandra/metrics + # Please avoid to scrape frequently those calls that are iterating over all sstables + + # Unaccessible metrics (not enough privilege) + - java:lang:memorypool:.*usagethreshold.* + + # Leaf attributes not interesting for us but that are presents in many path + - .*:999thpercentile + - .*:95thpercentile + - .*:fifteenminuterate + - .*:fiveminuterate + - .*:durationunit + - .*:rateunit + - .*:stddev + - .*:meanrate + - .*:mean + - .*:min + + # Path present in many metrics but uninterresting + - .*:viewlockacquiretime:.* + - .*:viewreadtime:.* + - .*:cas[a-z]+latency:.* + - .*:colupdatetimedeltahistogram:.* + + # Mostly for RPC, do not scrap them + - org:apache:cassandra:db:.* + + # columnfamily is an alias for Table metrics + # https://github.com/apache/cassandra/blob/8b3a60b9a7dbefeecc06bace617279612ec7092d/src/java/org/apache/cassandra/metrics/TableMetrics.java#L162 + - org:apache:cassandra:metrics:columnfamily:.* + + # Should we export metrics for system keyspaces/tables ? + - org:apache:cassandra:metrics:[^:]+:system[^:]*:.* + + # Don't scrap us + - com:criteo:nosql:cassandra:exporter:.* + + maxScrapFrequencyInSec: + 50: + - .* + + # Refresh those metrics only every hour as it is costly for cassandra to retrieve them + 3600: + - .*:snapshotssize:.* + - .*:estimated.* + - .*:totaldiskspaceused:.* +## @section TLS/SSL parameters +## + +## TLS/SSL parameters +## @param tls.internodeEncryption Set internode encryption +## @param tls.clientEncryption Set client-server encryption +## @param tls.autoGenerated Generate automatically self-signed TLS certificates. Currently only supports PEM certificates +## @param tls.existingSecret Existing secret that contains Cassandra Keystore and truststore +## @param tls.passwordsSecret Secret containing the Keystore and Truststore passwords if needed +## @param tls.keystorePassword Password for the keystore, if needed. +## @param tls.truststorePassword Password for the truststore, if needed. +## @param tls.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if tls.resources is set (tls.resources is recommended for production). +## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 +## @param tls.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) +## @param tls.certificatesSecret Secret with the TLS certificates. +## @param tls.tlsEncryptionSecretName Secret with the encryption of the TLS certificates +## +tls: + internodeEncryption: none + clientEncryption: false + autoGenerated: false + existingSecret: "" + passwordsSecret: "" + keystorePassword: "" + truststorePassword: "" + certificatesSecret: "" + tlsEncryptionSecretName: "" + resourcesPreset: "nano" + ## 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:'. + ## Example: + ## resources: + ## requests: + ## cpu: 2 + ## memory: 512Mi + ## limits: + ## cpu: 3 + ## memory: 1024Mi + resources: {} diff --git a/compose/ansible.cfg b/compose/ansible.cfg new file mode 100644 index 0000000..cdc7912 --- /dev/null +++ b/compose/ansible.cfg @@ -0,0 +1,28 @@ +[defaults] +ansible_managed="Ansible managed" +host_key_checking=false +inventory=./inventory/hosts +timeout = 60 +roles_path = ./roles/ +retry_files_enabled = False +#log_path = ./logs/ansible.log +become = True +become_user = root +become_method = sudo +#vault_password_file = ~/.netdev_vault +forks = 100 +pipelining = True +#Gathered facts caching +#gathering = smart +#fact_caching = jsonfile +#fact_caching_connection = ./.cache +#Never expires +fact_caching_timeout = 0 +#Profiler +callbacks_enabled = timer, profile_tasks, profile_roles +[ssh_connection] +pipelining = True +#Hold ssh ssh_connection +#ssh_args = "-o ControlMaster=auto -o ControlPersist=15m" +#Speed up files transfer +transfer_method = piped \ No newline at end of file diff --git a/compose/custom_inventory/group_vars/all/all.yaml b/compose/custom_inventory/group_vars/all/all.yaml new file mode 100644 index 0000000..a3bc616 --- /dev/null +++ b/compose/custom_inventory/group_vars/all/all.yaml @@ -0,0 +1 @@ +domain_name: "co-work.ru" \ No newline at end of file diff --git a/compose/custom_inventory/host_vars/cw-sya-reg-001/common.yml b/compose/custom_inventory/host_vars/cw-sya-reg-001/common.yml new file mode 100755 index 0000000..2b0d501 --- /dev/null +++ b/compose/custom_inventory/host_vars/cw-sya-reg-001/common.yml @@ -0,0 +1,4 @@ +--- +#host_name: "cw-sya-reg-001" +ansible_hostname: "docker.stage.co-work.local" +ansible_host: "10.130.0.42" diff --git a/compose/custom_inventory/host_vars/cw-sya-reg-001/files/ssl/docker.crt b/compose/custom_inventory/host_vars/cw-sya-reg-001/files/ssl/docker.crt new file mode 100644 index 0000000..dc302b6 --- /dev/null +++ b/compose/custom_inventory/host_vars/cw-sya-reg-001/files/ssl/docker.crt @@ -0,0 +1,78 @@ +$ANSIBLE_VAULT;1.1;AES256 +39643962356131303761633334643262366464336364326535653733613031303462623037313636 +6466646332613364346437626465613039383132313335330a623837393332353363316536653661 +64373039653131386432643162646534386130373335326630343339353665353639383337336230 +3166656431363264620a333563346663323035643538646435323263636462386237356164383561 +32613835616630643938356461646663363033613663373139643865303430613137376563313133 +64313664393633386138363837653966303039363231616461336466623236643564353830353764 +34663938343938626264393165313732333864356335303239626234613766616266393930633339 +61326633333034626639346662323939373366363735353936306130343534376362396561653730 +34666632353539366165353637326237636437373135353062373733366238386233353430623163 +61346132373935653431373033623937376465323763313065396162643138333262326366396333 +33653462633532656263303366646663313735376333303964396534333134333532343865313564 +61613830323234663938373863666563306332613737346639356630333738633563333733373066 +31323937636631616533643963386437386335383265663539356238396133376464613362653233 +39346566393833383265316461633433343666613033663433616237636364373863653766333062 +36643535653365363862643761393264346365373531656130383838363665636534303736353535 +61653465396264386263373365613066333035393633643030383462613665346636386161303963 +37326665333937653866613164383835363062623332323939376162336462653830333135353937 +38336364653662373838643666353236363064353563626666363630363733323530393766333535 +66366335353737653435303861303462336366623765333635643135393163656663666138653731 +61346365346561623162333231666435323664653132386162626333343966333938653336373565 +61663964643737656232633363336535653861616266346130303164333766333432663462356635 +66623836326163666463336437336135373865343462313134376534383963383461626462396362 +30613234633038626539323434306465383036613334626433343932383132306433646161366230 +39666465313530646536356265653264366237383136636466393164646535663164396663306531 +30346336393263363630633835383266623736633866336635643531326366346366386630383132 +66303566306233393238626465346331383630306238353734323739383536633535303134636666 +64393235643034633030656432386162396236323965356637666162303666336239343766666261 +63363336653733366166383865366164353064333965663364623435613430643261393330646163 +61326333376532356237356264363335383465666362623965663035356132633534643230306334 +61333037396637353239323837636238633137613035653034376330383934356237656133326138 +61383136326431343337656564356464363434623330356464643762643930363139613865323461 +33393439323836333164656365343134313166646235373263666438333936613465386530306634 +32306364356564376661343061363462313539623238363562373535616565333239356365663338 +30323362626136393335643238383930316266383362633865323965643133376331346638373865 +32663434623364326339336437383366386539373930663365376437613461376366326133663634 +38303861656464383866633732306366363633323165363438623462383838653130376136656139 +31343263393561616663376331366534636239386638633032366563626634346664626432363735 +30623133383234666537623237653132386364313562373833633138336362366537663633383830 +34313837653866333838373063623032383037653163313536646162653731623538636664623038 +37326664393435316134393636303133393364323361633731316465373964373365643738656339 +33343330613432613362336633323362366134666636376564353033333033653339336362623838 +66366435393564376666356265343365653130626336313132343234663465383630636662376532 +31656431373263666339623434333263363135383038636232623338623562343036653635646632 +30653663353835343633653434383362663830643030363164616163613839383133656533343632 +33373132326362636165616134643065323364623430353565643136313239353336663438656532 +39343236306565336430656339633338623731616637303834323363643834363665656433363432 +36346331383134623732363864663537343265323033643330383763313862326235363462353533 +36646233343562356534333839323763613836316435323163346235323862386164613935336137 +37306536613930343938373130366235376264323766313932646361623965376563386632303536 +61626462633262343035336537353762663930386266653363313535313433306539306465663235 +38333237656334313637386235613230356233646533363332383536663164626433303561396466 +39653662373933316461386639633362316264373230613562303966353165366636383738373962 +36386634323236623165303339663936613936313761313730346233313632373563643439396565 +37663035626434343965316230383465303732386437333039323239643537373035613632383039 +34666334383062363232333331653161343431373534633739363665333634343134633964646137 +37363333653939633232623838383430633135643732363166366538313331343063363131356438 +36666165313835316135386337303566613934343335313937313339633838363039356665373631 +63636565613439633961363562613632636330666637383538303062653965373034306164333637 +30313131353038383735346335376231623463646234626266313633643462373761333931366637 +32663232346530383835333466643230306238656638336231636131323061623566376331626635 +34363264363133376266343864333435356631366465666239326666386233626263373231363963 +32656634383966666533656662396635373732303036666664306266313362333362633466613864 +64376361376562343864653364383731386465386361383433386531323835646535663031656636 +65626561333434646665346466393439333437386239346665646464393738383939336238383037 +64643263303238326431326537373932336630363363386435383063376664323431363836346538 +33366437306666643965633833663033653962353731313435303635666539646633366639313135 +62393266303836386461653965333435303764336637663737356666333632613834303865633937 +38663338363231336430376537616436316661333636326130336136613436343166666338653733 +38366539383132353939373665313935623566323539356336613466336661316138373535303463 +33323165366261613434663465653364343362306632333466356662383361626565303834396661 +63313137376266666530313739663766323864323561666139623063636539646431393862613335 +38633331323161333961346133623666353934343038623566326237663362323832303738396264 +36623333316632376533353265613031353039343362333234613964613738393162383735653565 +30663266633637636230346237336338383439306638626537363763373364633837363464313439 +61343062356432623932393138616261663861373661303636343239366337326230643739313962 +32656232353362383031616266623534626233316164383232363537343837313662323736646136 +6439 diff --git a/compose/custom_inventory/host_vars/cw-sya-reg-001/files/ssl/docker.key b/compose/custom_inventory/host_vars/cw-sya-reg-001/files/ssl/docker.key new file mode 100644 index 0000000..41df8e7 --- /dev/null +++ b/compose/custom_inventory/host_vars/cw-sya-reg-001/files/ssl/docker.key @@ -0,0 +1,90 @@ +$ANSIBLE_VAULT;1.1;AES256 +39663733323038363234363735323432656436633630376634333137363236373534633532373532 +6364623835383366363833386362656633373133613032650a313531306532306161333066396364 +30356364346362613932363732643335313361653137626462343663323938363962373939666230 +6466656531653464360a366135323161353466646461313762303535303266356238663866373835 +65623362383638326462343738646436363666396566346238313666326435623238636338363637 +66343766366139623238346135636437376436633531623666396132323236323361366661616166 +34386233613430323636313031323966306438626535366630346163343430663662633531373433 +62396536656635373634343332353038343136633330396332343365353631396434326266313332 +39626533393163313233366337633661623432653334666630363865306431623332393438316132 +66333130383166326336656565383266663835613137343537643265656263363031663333646265 +30376466356637613738666262313539363034653765346137316465613836613631303434353530 +37383761343162366430333539323130653664653134303739333033356464373837366433616265 +39333461313536386138346663313339306232353130386531303235633566376366343333333630 +33353238326439393531633437353966623337636538633735663038303837346134333864366332 +30653466376136366461663537393062646464373136356138623631663534383363366265373366 +36356362306239306331336337333864663631646232653164313936373362396232643730316236 +30333864316635323332323839373366623933386531643064626362303635373866653433616237 +65386237393036333934653066653237383934363165323535643265623833383830613365336465 +30626635656461356332393864646437363939633937353632646464393236373233306136623263 +38343261366664663561333638366165636330326162613661323562663239613435353966646562 +31306338653464373534356162376639396265633036633265643361626362333432636336373937 +62633664313639663939353632336666613332376263633933613537623131373966366139303731 +39623236313961663336303539626637623838646537306464333736306636636531353463636537 +63363865376631316337636236373563663636636564646665373566663534323339626237393133 +66396231393761303730366236313634336662613539636161623139636561373734306566336430 +32313938666434663231396165363733613464353930393939343536366631626465623035353033 +62646366623937643537383634616262316362316164653832396437356235623066356537623430 +32636462333330333464366634643736633937303837346238333635636430316363323230376537 +39333763626666643165613330303033343838616631353038636138336232303562643962303938 +62313762303861303539386333323031326338643665346630383938356362383738346163316563 +33353234653632383163383961363732393935396437623538623763353636643035396563343666 +30623631643731646337623062326562376665303764383135383361616365623132646138393664 +39636135366336653433393232373864356631663062366437663532666632353737366635346635 +63633363366565666132356366373461383339373036383532346636623837363831613338396333 +62626162393263313666616662623962356663666264373933663339363834653136633064333563 +33396432663830346563376561653364373637663539356564393462363432623731653533343637 +32376135356661363835663733636266393430383035613365656432393330326266353339383832 +37666162623738363538313132373034623234313733646532626162343931313066316436303036 +66363462333435393433666133643230316464646366633866356637396565643739643938633230 +33306264613738376361376630613932366234623739356564323137326566326233393230383532 +33613932323262616362616163383934313662343262646634626364353735643465343466366137 +34333162643965643361393031333836653334376236616634356665343534366230383263636638 +64333837333330316130356634613133636232396462393237313134656234616237666435656431 +61663938666533376433363531333663643266376164323163653537356532316462376330393434 +34333962323634643535383133353963323062303532623539613833366363323730646330343064 +37643136386164376434613531373438383331356661393637616630386161356339316130333861 +36343837636539636431303864646463666134663465363638323861316164653931323335343038 +63646264363132326234306566643336326564376134313739373938363835333264643539323834 +63363461323736306539663439626435353761643963346633396231336235316362343736383563 +63313938326561313264646536353232663635383164623733343962313733376539373830306366 +32363337303935623534386365353934353437356361366538353064663231356665306232386235 +65633837633438643431303935376535623439393931306566356538613363623333396161336531 +66653833616634623630656465363262326334666236393539303032646565353838643963646635 +64626533643432383137316165306662336562346537323066396638336266643033613836653034 +62373036373738626430343834633730326537656239343165386137623935363366373133393531 +33643565633038666438653235623039356665306130323635643230636133323536663635656630 +33333964633138666236623835633435313862326136343165353462363039663766633061663235 +32626539323264643536363666333238326362313333646235643064373863336334666432623361 +63316634313964633762613163313866373038623839383834643066313337386164636638323965 +36643661613965336366326663656536386436303038666235623836396333636265373837613036 +61333334656562323232656161316639393561333035383735393437346336393262663265343135 +38633330646265333733343337393833633964326139643966306130646663343432343638323035 +62383464333538633362316634643736643736393534373364323338623962636537383030336232 +37323637393735303531646165653563653365393665633337303762396136656166353836336436 +39643537633063626431363530616335393836653036363335333262616363623163396662383036 +36656533316164353530366639346132353731646332653938653636666463663661383864376464 +61316361373330633165363330643666313931326336303436323031386436646434613330366665 +66653731393638303139663230346536303937643461616366613738383862636634363435386133 +37663235663231343261336338373335616330626162363539313634346637373961613031306136 +33323866313634333131373864353862656362333536366465646435346565303636383362303634 +36356433623233363837316435636533363562663234336137333435363533626661666536376461 +32646464643130333930323537613063646635393534366462346539386131626139646562323134 +63613263333832366264343966383163393232636662646361643162323637653765643730613832 +31353665633262313065323064376536656433666563383834343139653939656639656339366362 +38666566323861666330636435363864346238363438343630306665666662663663393566366662 +65373763326432396334306265633936353234343265353936373837656362653963363065356264 +38343166346235333266353264633031343462373931616635306330636262646565653537316462 +66656563346633666464633461663533353831636238336232303161646336366134343066646337 +36663636626439383939336636383236663962393539633737396537353539666237646334616637 +36643335313239376138376634366232623037376138376161313737383562646366323632633866 +66333639313539653833316462653937386132323134346663346333383964336130333964633031 +39373663306161613339356636623630353336393366323139326538323539373630396531343435 +64313363663165643539323431383631343035656432663366643861343166616131613464613334 +30643638316431363865613862383339386431666164626264646533323136383734323730613433 +38626561363534333765333235343261616565383236363035663563316232363038386239303738 +35623165393566333837343862313961633238313938346632636166346430313631346130383134 +36353364393237333837393466653137356538613362613663326162666533393830613530666432 +37613835353739326162633737393538393965653266333637376536663631393838313561343235 +63323266653335643762373964366639343566383362393132643434336135333066 diff --git a/compose/custom_inventory/hosts b/compose/custom_inventory/hosts new file mode 100755 index 0000000..a0f7217 --- /dev/null +++ b/compose/custom_inventory/hosts @@ -0,0 +1,18 @@ +[wireguard_servers] +gt-demo-vpn ansible_host=10.212.0.13 #34.18.24.128 +gt-demo-reg ansible_host=10.212.0.7 + +[gemteam_demo] +gt-demo-vpn ansible_host=10.212.0.13 #34.18.24.128 +gt-demo-dns ansible_host=10.212.0.4 +gt-demo-mon ansible_host=10.212.0.15 +gt-demo-ldap ansible_host=10.212.0.3 +gt-demo-iam ansible_host=10.212.0.5 +gt-demo-jfrog ansible_host=10.212.0.6 +gt-demo-reg ansible_host=10.212.0.7 +gt-demo-docker ansible_host=10.212.0.8 +gt-demo-jenkins-m ansible_host=10.212.0.9 +gt-demo-jenkins-w ansible_host=10.212.0.11 +gt-demo-store ansible_host=10.212.0.10 +gt-demo-livekit ansible_host=10.212.0.12 +gt-demo-front ansible_host=10.212.0.14 \ No newline at end of file diff --git a/compose/inventory/hosts b/compose/inventory/hosts new file mode 100644 index 0000000..17cabc9 --- /dev/null +++ b/compose/inventory/hosts @@ -0,0 +1,8 @@ +[co-work_stage] +cw-sya-ldap-001 ansible_host=10.130.0.16 +cw-sya-nfs-001 ansible_host=10.130.0.37 +cw-sya-store-001 ansible_host=10.130.0.12 +cw-sya-vpn-001 ansible_host=10.130.0.28 +cw-sya-iam-001 ansible_host=10.130.0.41 +cw-sya-reg-001 ansible_host=10.130.0.42 + diff --git a/compose/playbooks/ca_server/README.md b/compose/playbooks/ca_server/README.md new file mode 100644 index 0000000..bf4e3d3 --- /dev/null +++ b/compose/playbooks/ca_server/README.md @@ -0,0 +1,4 @@ +====================================================================== +Playbook information +====================================================================== +Плейбук по установке и настройке Центра сертификации (OpenSSL) \ No newline at end of file diff --git a/compose/playbooks/ca_server/ansible.cfg b/compose/playbooks/ca_server/ansible.cfg new file mode 100644 index 0000000..20d7065 --- /dev/null +++ b/compose/playbooks/ca_server/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +ansible_managed="Ansible managed" +host_key_checking=False +inventory=inventory/hosts diff --git a/compose/playbooks/ca_server/defaults/main.yml b/compose/playbooks/ca_server/defaults/main.yml new file mode 100644 index 0000000..11163dc --- /dev/null +++ b/compose/playbooks/ca_server/defaults/main.yml @@ -0,0 +1,9 @@ +--- +# defaults vars +# ansible_python_interpreter: "/usr/libexec/platform-python" +ansible_ssh_pipelining: "true" +ansible_user: "gem-admin" +ansible_ssh_transfer_method: "piped" +ansible_ssh_common_args: "-o StrictHostKeyChecking=no" +ansible_port: 22 + diff --git a/compose/playbooks/ca_server/handlers/main.yml b/compose/playbooks/ca_server/handlers/main.yml new file mode 100644 index 0000000..c09dec7 --- /dev/null +++ b/compose/playbooks/ca_server/handlers/main.yml @@ -0,0 +1,5 @@ +--- +# handlers file + + + diff --git a/compose/playbooks/ca_server/inventory/hosts b/compose/playbooks/ca_server/inventory/hosts new file mode 100644 index 0000000..9318e56 --- /dev/null +++ b/compose/playbooks/ca_server/inventory/hosts @@ -0,0 +1,3 @@ + +[ca-host] +cw-sya-ldap-001 ansible_host=10.130.0.16 \ No newline at end of file diff --git a/compose/playbooks/ca_server/main.yml b/compose/playbooks/ca_server/main.yml new file mode 100644 index 0000000..742748d --- /dev/null +++ b/compose/playbooks/ca_server/main.yml @@ -0,0 +1,16 @@ +--- +# Установка центра сертификации +- name: Install CA server + hosts: cw-sya-ldap-001 + gather_facts: true + become: true + vars_files: + - vars/base_conf.yml + - vars/secret.yml + - defaults/main.yml + pre_tasks: + - import_tasks: tasks/check_os_version.yml + roles: + - role: ca_install + when: ansible_distribution == "Ubuntu" + diff --git a/compose/playbooks/ca_server/roles/ca_install/README.md b/compose/playbooks/ca_server/roles/ca_install/README.md new file mode 100644 index 0000000..9b11033 --- /dev/null +++ b/compose/playbooks/ca_server/roles/ca_install/README.md @@ -0,0 +1,4 @@ +====================================================================== +Role information +====================================================================== +Установка CA (Центра сертификации) \ No newline at end of file diff --git a/compose/playbooks/ca_server/roles/ca_install/handlers/main.yml b/compose/playbooks/ca_server/roles/ca_install/handlers/main.yml new file mode 100644 index 0000000..7479ceb --- /dev/null +++ b/compose/playbooks/ca_server/roles/ca_install/handlers/main.yml @@ -0,0 +1,4 @@ +--- +# handlers file + + diff --git a/compose/playbooks/ca_server/roles/ca_install/tasks/configure_ca.yml b/compose/playbooks/ca_server/roles/ca_install/tasks/configure_ca.yml new file mode 100644 index 0000000..e7d2760 --- /dev/null +++ b/compose/playbooks/ca_server/roles/ca_install/tasks/configure_ca.yml @@ -0,0 +1,51 @@ +--- +# Настройка CA +- name: Configure CA + block: + - name: Creates base directory + ansible.builtin.file: + path: "/opt/{{ item }}" + state: directory + loop: + - CA + - CA/service + + - name: Check CA private key + stat: + path: /opt/CA/RootCA.key + register: ca_key_result + + - name: Create CA private key + expect: + command: /bin/bash -c 'openssl genpkey -algorithm RSA -out /opt/CA/RootCA.key -aes-128-cbc' + responses: + Enter PEM pass *: "{{ ca_password }}" + Verifying *: "{{ ca_password }}" + timeout: 300 + when: ca_key_result.stat.exists == false + + - name: Check CA certificate + stat: + path: /opt/CA/RootCA.crt + register: ca_crt_result + + - name: Create CA certificate + expect: + command: "/bin/bash -c 'openssl req -x509 -new -key /opt/CA/RootCA.key -sha256 -days {{ ca_lifeday }} -out /opt/CA/RootCA.crt'" + responses: + Enter pass *: "{{ ca_password }}" + Country *: "{{ ca_country }}" + State *: "{{ ca_state }}" + Locality *: "{{ ca_locality }}" + Organization *: "{{ ca_organization }}" + Organizational *: "{{ ca_organization }}" + Common *: "{{ ca_domain }}" + Email *: "admin@{{ ca_domain }}" + timeout: 300 + when: ca_crt_result.stat.exists == false + + - name: Create certificate template + template: + src: template.cnf.j2 + dest: /opt/CA/template.cnf + register: template_updated diff --git a/compose/playbooks/ca_server/roles/ca_install/tasks/create_cert.yml b/compose/playbooks/ca_server/roles/ca_install/tasks/create_cert.yml new file mode 100644 index 0000000..7410fd4 --- /dev/null +++ b/compose/playbooks/ca_server/roles/ca_install/tasks/create_cert.yml @@ -0,0 +1,45 @@ +--- +- name: Create wildcard service certificate + block: + - name: Check private KEY + stat: + path: /opt/CA/service/{{ crt_services }}.key + register: key_result + + - name: Create wildcard service KEY + shell: | + openssl genpkey -algorithm RSA -out /opt/CA/service/{{ crt_services }}.key + when: key_result.stat.exists == false + + - name: Check CSR + stat: + path: /opt/CA/service/{{ crt_services }}.csr + register: csr_result + + - name: Create wildcard service CSR + expect: + command: "/bin/bash -c 'openssl req -new -key /opt/CA/service/{{ crt_services }}.key -config /opt/CA/template.cnf -reqexts req_ext -out /opt/CA/service/{{ crt_services }}.csr'" + responses: + Country *: "{{ ca_country }}" + State *: "{{ ca_state }}" + Locality *: "{{ ca_locality }}" + Organization *: "{{ ca_organization }}" + Organizational *: "{{ ca_organization }}" + Common *: "{{ ca_domain }}" + Email *: "admin@{{ ca_domain }}" + timeout: 300 + when: csr_result.stat.exists == false + + - name: Check public CRT + stat: + path: /opt/CA/service/{{ crt_services }}.crt + register: crt_result + + - name: Create wildcard service CRT + expect: + command: "/bin/bash -c 'openssl x509 -req -days 730 -CA /opt/CA/RootCA.crt -CAkey /opt/CA/RootCA.key -extfile /opt/CA/template.cnf -extensions req_ext -in /opt/CA/service/{{ crt_services }}.csr -out /opt/CA/service/{{ crt_services }}.crt'" + responses: + Enter pass *: "{{ ca_password }}" + when: crt_result.stat.exists == false + + diff --git a/compose/playbooks/ca_server/roles/ca_install/tasks/main.yml b/compose/playbooks/ca_server/roles/ca_install/tasks/main.yml new file mode 100644 index 0000000..6dae5c5 --- /dev/null +++ b/compose/playbooks/ca_server/roles/ca_install/tasks/main.yml @@ -0,0 +1,8 @@ +--- + +# Настройка CA +- name: Configure CA + include_tasks: configure_ca.yml + +- name: Create service certificate + include_tasks: create_cert.yml diff --git a/compose/playbooks/ca_server/roles/ca_install/templates/template.cnf.j2 b/compose/playbooks/ca_server/roles/ca_install/templates/template.cnf.j2 new file mode 100644 index 0000000..f403563 --- /dev/null +++ b/compose/playbooks/ca_server/roles/ca_install/templates/template.cnf.j2 @@ -0,0 +1,22 @@ +[ req ] +default_bits = 2048 +distinguished_name = req_distinguished_name +req_extensions = req_ext +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = {{ ca_country }} +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = {{ ca_state }} +localityName = Locality Name (eg, city) +localityName_default = {{ ca_locality }} +organizationName = Organization Name (eg, company) +organizationName_default = {{ ca_organization }} +commonName = Common Name (eg, YOUR name or FQDN) +commonName_max = 64 +commonName_default = *.{{ ca_domain }} +[ req_ext ] +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectAltName = @alt_names +[alt_names] +DNS.1 = *.{{ ca_domain }} diff --git a/compose/playbooks/ca_server/roles/ca_install/vars/main.yml b/compose/playbooks/ca_server/roles/ca_install/vars/main.yml new file mode 100644 index 0000000..fa2fb4c --- /dev/null +++ b/compose/playbooks/ca_server/roles/ca_install/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file diff --git a/compose/playbooks/ca_server/tasks/check_os_version.yml b/compose/playbooks/ca_server/tasks/check_os_version.yml new file mode 100644 index 0000000..2909c8b --- /dev/null +++ b/compose/playbooks/ca_server/tasks/check_os_version.yml @@ -0,0 +1,15 @@ +--- +# Проверка версии ОС +- name: Check OS version + block: + # - name: DEBUG OS version + # debug: + # msg: + # - "OS: {{ ansible_distribution }}" + # - "Version: {{ ansible_distribution_version }}" + # - "Major version: {{ ansible_distribution_major_version }}" + + - name: OS version not supported + fail: + msg: "Operating system {{ ansible_distribution }} ver. {{ ansible_distribution_major_version }} not supported" + when: ansible_distribution not in ['Ubuntu'] \ No newline at end of file diff --git a/compose/playbooks/ca_server/vars/base_conf.yml b/compose/playbooks/ca_server/vars/base_conf.yml new file mode 100644 index 0000000..add039b --- /dev/null +++ b/compose/playbooks/ca_server/vars/base_conf.yml @@ -0,0 +1,10 @@ +--- +# Переменные конфигурации +ca_domain: "stage.co-work.local" # Имя доменна +ca_country: "RU" # Страна +ca_locality: "Moscow" +ca_state: "Moscow" +ca_organization: "co-work_stage" # Имя организации +ca_lifeday: "3650" # Срок жизни рутового сертификата +crt_services: "wc" # Имя wildcard сертификата + \ No newline at end of file diff --git a/compose/playbooks/ca_server/vars/secret.yml b/compose/playbooks/ca_server/vars/secret.yml new file mode 100644 index 0000000..e896bc3 --- /dev/null +++ b/compose/playbooks/ca_server/vars/secret.yml @@ -0,0 +1,10 @@ +$ANSIBLE_VAULT;1.1;AES256 +32393233636236623437333934643231303835343237373436333735333939326635316636613433 +6137623638653763323232323831323537383561616361660a376136633637616165366362323065 +35336532623538336364636566633339316263653761383733643834633765313831333234663666 +6561343033383266660a363530616230396537623165326465326662353234383166356264306265 +61396233623233363933343932303733656630653633633938306230383933393433633266666133 +35313338326330636632346132336665636231313836393336346230303662356562363937303932 +31323466633735383738656264383066363231353561373635386461643865353235393661326435 +65353630383932613432376137376564623236623037623261663766356236363438383064663062 +3031 diff --git a/compose/playbooks/dns_server/README.md b/compose/playbooks/dns_server/README.md new file mode 100644 index 0000000..57b0732 --- /dev/null +++ b/compose/playbooks/dns_server/README.md @@ -0,0 +1,4 @@ +====================================================================== +Playbook information +====================================================================== +Плейбук по установке и настройке DNS сервера BIND \ No newline at end of file diff --git a/compose/playbooks/dns_server/ansible.cfg b/compose/playbooks/dns_server/ansible.cfg new file mode 100644 index 0000000..20d7065 --- /dev/null +++ b/compose/playbooks/dns_server/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +ansible_managed="Ansible managed" +host_key_checking=False +inventory=inventory/hosts diff --git a/compose/playbooks/dns_server/defaults/main.yml b/compose/playbooks/dns_server/defaults/main.yml new file mode 100644 index 0000000..11163dc --- /dev/null +++ b/compose/playbooks/dns_server/defaults/main.yml @@ -0,0 +1,9 @@ +--- +# defaults vars +# ansible_python_interpreter: "/usr/libexec/platform-python" +ansible_ssh_pipelining: "true" +ansible_user: "gem-admin" +ansible_ssh_transfer_method: "piped" +ansible_ssh_common_args: "-o StrictHostKeyChecking=no" +ansible_port: 22 + diff --git a/compose/playbooks/dns_server/handlers/main.yml b/compose/playbooks/dns_server/handlers/main.yml new file mode 100644 index 0000000..c09dec7 --- /dev/null +++ b/compose/playbooks/dns_server/handlers/main.yml @@ -0,0 +1,5 @@ +--- +# handlers file + + + diff --git a/compose/playbooks/dns_server/inventory/hosts b/compose/playbooks/dns_server/inventory/hosts new file mode 100644 index 0000000..35b252b --- /dev/null +++ b/compose/playbooks/dns_server/inventory/hosts @@ -0,0 +1,3 @@ + +[dns-host] +cw-sya-ldap-001 ansible_host=10.130.0.16 \ No newline at end of file diff --git a/compose/playbooks/dns_server/main.yml b/compose/playbooks/dns_server/main.yml new file mode 100644 index 0000000..e681e68 --- /dev/null +++ b/compose/playbooks/dns_server/main.yml @@ -0,0 +1,16 @@ +--- +# Установка DNS сервера Bind +- name: Install DNS server Bind + hosts: cw-sya-ldap-001 + gather_facts: true + become: true + vars_files: + - vars/base_conf.yml + - vars/dns_zone.yml + - defaults/main.yml + pre_tasks: + - import_tasks: tasks/check_os_version.yml + roles: + - role: bind_install + when: ansible_distribution == "Ubuntu" + diff --git a/compose/playbooks/dns_server/roles/bind_install/README.md b/compose/playbooks/dns_server/roles/bind_install/README.md new file mode 100644 index 0000000..10f7939 --- /dev/null +++ b/compose/playbooks/dns_server/roles/bind_install/README.md @@ -0,0 +1,4 @@ +====================================================================== +Role information +====================================================================== +Установка Bind \ No newline at end of file diff --git a/compose/playbooks/dns_server/roles/bind_install/handlers/main.yml b/compose/playbooks/dns_server/roles/bind_install/handlers/main.yml new file mode 100644 index 0000000..7479ceb --- /dev/null +++ b/compose/playbooks/dns_server/roles/bind_install/handlers/main.yml @@ -0,0 +1,4 @@ +--- +# handlers file + + diff --git a/compose/playbooks/dns_server/roles/bind_install/tasks/configure_bind.yml b/compose/playbooks/dns_server/roles/bind_install/tasks/configure_bind.yml new file mode 100644 index 0000000..4b58cc3 --- /dev/null +++ b/compose/playbooks/dns_server/roles/bind_install/tasks/configure_bind.yml @@ -0,0 +1,124 @@ +--- +# Настройка Bind +- name: Configure Bind + block: + - name: Change bind options config + template: + src: named.conf.options.j2 + dest: /etc/bind/named.conf.options + mode: 0644 + owner: root + group: bind + register: named_options_updated + + - name: Change bind local config + template: + src: named.conf.local.j2 + dest: /etc/bind/named.conf.local + mode: 0644 + owner: root + group: bind + register: named_local_updated + + - name: Creates master zone directory + ansible.builtin.file: + path: /var/cache/bind/master + state: directory + + - name: Create dns local zone config + template: + src: dns_zone_local.j2 + dest: "/var/cache/bind/master/{{ dns_zone }}" + mode: 0644 + owner: root + group: bind + register: named_zone_updated + + - name: Check and update zone config + shell: | + named-checkzone {{ dns_zone }} /var/cache/bind/master/{{ dns_zone }} + when: named_zone_updated['changed'] + + - name: Update DNS zone + shell: | + rndc reload + when: named_zone_updated['changed'] + + - name: Check Bind config + shell: "named-checkconf /etc/bind/named.conf" + when: named_options_updated['changed'] or named_local_updated['changed'] + + - name: Reload Bind service + service: + name: bind9 + state: reloaded + when: named_options_updated['changed'] or named_local_updated['changed'] or named_zone_updated['changed'] + +- name: Configure ufw + block: + - name: Install ufw packages + apt: + name: '{{ item }}' + state: present + update_cache: yes + loop: + - ufw + when: "'ufw' not in ansible_facts.packages" + + - name: Enable ufw service + systemd: + name: ufw.service + state: started + enabled: yes + + - name: Default allow outgoing traffic + community.general.ufw: + default: allow + direction: outgoing + + - name: Default deny incoming traffic + community.general.ufw: + default: deny + direction: incoming + + - name: Allow ssh traffic + community.general.ufw: + rule: allow + port: 22 + proto: tcp + + - name: Allow DNS traffic TCP + community.general.ufw: + rule: allow + port: 53 + proto: tcp + + - name: Allow DNS traffic UDP + community.general.ufw: + rule: allow + port: 53 + proto: udp + + - name: Enable UFW + community.general.ufw: + state: enabled + policy: deny + + # - name: Enable and start Docker service + # service: + # name: docker + # state: started + # enabled: yes + + # - name: Restart Docker service + # service: + # name: docker + # state: restarted + # when: docker_updated['changed'] + + # - name: Add users to a docker group + # ansible.builtin.user: + # name: "{{ item }}" + # groups: docker + # loop: "{{ docker_users_list }}" + # when: docker_users_list is defined \ No newline at end of file diff --git a/compose/playbooks/dns_server/roles/bind_install/tasks/install_bind.yml b/compose/playbooks/dns_server/roles/bind_install/tasks/install_bind.yml new file mode 100644 index 0000000..c3c6fcd --- /dev/null +++ b/compose/playbooks/dns_server/roles/bind_install/tasks/install_bind.yml @@ -0,0 +1,17 @@ +--- +# Установка Bind +- name: "Check packages is installed" + package_facts: + manager: "auto" + +- name: "Install packages" + block: + - name: Install packages + apt: + name: '{{ item }}' + state: present + update_cache: yes + loop: + - bind9 + - dnsutils + when: "'bind9' not in ansible_facts.packages or 'dnsutils' not in ansible_facts.packages" \ No newline at end of file diff --git a/compose/playbooks/dns_server/roles/bind_install/tasks/main.yml b/compose/playbooks/dns_server/roles/bind_install/tasks/main.yml new file mode 100644 index 0000000..7e255c7 --- /dev/null +++ b/compose/playbooks/dns_server/roles/bind_install/tasks/main.yml @@ -0,0 +1,9 @@ +--- + +# Установка Bind +- name: Install Bind + include_tasks: install_bind.yml + +# Настройка Bind +- name: Configure Bind + include_tasks: configure_bind.yml diff --git a/compose/playbooks/dns_server/roles/bind_install/templates/dns_zone_local.j2 b/compose/playbooks/dns_server/roles/bind_install/templates/dns_zone_local.j2 new file mode 100644 index 0000000..7c33d19 --- /dev/null +++ b/compose/playbooks/dns_server/roles/bind_install/templates/dns_zone_local.j2 @@ -0,0 +1,17 @@ +$TTL 14400 + +{{ dns_zone }}. IN SOA {{ ansible_hostname }}.{{ dns_zone }}. admin.{{ dns_zone }}. ( + 2017082401 ; Serial + 10800 ; Refresh + 3600 ; Retry + 604800 ; Expire + 604800 ; Negative Cache TTL +) + + IN NS {{ ansible_hostname }}.{{ dns_zone }}. + + +@ IN A {{ ansible_default_ipv4.address }} +localhost IN A 127.0.0.1 +{{ ansible_hostname }} IN A {{ ansible_default_ipv4.address }} +{{ dns_rec }} diff --git a/compose/playbooks/dns_server/roles/bind_install/templates/named.conf.local.j2 b/compose/playbooks/dns_server/roles/bind_install/templates/named.conf.local.j2 new file mode 100644 index 0000000..eab046b --- /dev/null +++ b/compose/playbooks/dns_server/roles/bind_install/templates/named.conf.local.j2 @@ -0,0 +1,6 @@ +zone "{{ dns_zone }}" { + type master; + file "master/{{ dns_zone }}"; + allow-transfer { {{ ansible_default_ipv4.address }}; }; + allow-update { none; }; +}; \ No newline at end of file diff --git a/compose/playbooks/dns_server/roles/bind_install/templates/named.conf.options.j2 b/compose/playbooks/dns_server/roles/bind_install/templates/named.conf.options.j2 new file mode 100644 index 0000000..e6ab096 --- /dev/null +++ b/compose/playbooks/dns_server/roles/bind_install/templates/named.conf.options.j2 @@ -0,0 +1,12 @@ +options { + directory "/var/cache/bind"; + listen-on { + {{ ansible_default_ipv4.address }}; + }; + listen-on-v6 { none; }; + allow-query { any; }; + forwarders { + {{ ext_forward_dns1 }}; + {{ ext_forward_dns2 }}; + }; +}; \ No newline at end of file diff --git a/compose/playbooks/dns_server/roles/bind_install/vars/main.yml b/compose/playbooks/dns_server/roles/bind_install/vars/main.yml new file mode 100644 index 0000000..fa2fb4c --- /dev/null +++ b/compose/playbooks/dns_server/roles/bind_install/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file diff --git a/compose/playbooks/dns_server/tasks/check_os_version.yml b/compose/playbooks/dns_server/tasks/check_os_version.yml new file mode 100644 index 0000000..2909c8b --- /dev/null +++ b/compose/playbooks/dns_server/tasks/check_os_version.yml @@ -0,0 +1,15 @@ +--- +# Проверка версии ОС +- name: Check OS version + block: + # - name: DEBUG OS version + # debug: + # msg: + # - "OS: {{ ansible_distribution }}" + # - "Version: {{ ansible_distribution_version }}" + # - "Major version: {{ ansible_distribution_major_version }}" + + - name: OS version not supported + fail: + msg: "Operating system {{ ansible_distribution }} ver. {{ ansible_distribution_major_version }} not supported" + when: ansible_distribution not in ['Ubuntu'] \ No newline at end of file diff --git a/compose/playbooks/dns_server/vars/base_conf.yml b/compose/playbooks/dns_server/vars/base_conf.yml new file mode 100644 index 0000000..63530bf --- /dev/null +++ b/compose/playbooks/dns_server/vars/base_conf.yml @@ -0,0 +1,5 @@ +--- +# Переменные конфигурации +ext_forward_dns1: "10.130.0.2" # Внешний DNS сервер для перенаправления запросов +ext_forward_dns2: "77.88.8.8" # Внешний DNS сервер для перенаправления запросов +dns_zone: "stage.co-work.local" # DNS зона \ No newline at end of file diff --git a/compose/playbooks/dns_server/vars/dns_zone.yml b/compose/playbooks/dns_server/vars/dns_zone.yml new file mode 100644 index 0000000..9919ae3 --- /dev/null +++ b/compose/playbooks/dns_server/vars/dns_zone.yml @@ -0,0 +1,16 @@ +dns_rec: | + cw-sya-vpn-001 IN A 10.130.0.28 + cw-sya-iam-001 IN A 10.130.0.41 + cw-sya-ldap-001 IN A 10.130.0.16 + ldap IN A 10.130.0.16 + iam IN A 10.130.0.41 + cw-sya-reg-001 IN A 10.130.0.42 + docker IN A 10.130.0.42 + cw-sya-nfs-001 IN A 10.130.0.37 + cw-sya-store-001 IN A 10.130.0.12 + store IN A 10.130.0.12 + cw-sya-kubb-001 IN A 10.130.0.20 + cw-sya-kubb-002 IN A 10.130.0.13 + cw-sya-kubb-003 IN A 10.130.0.23 + argocd IN A 10.130.0.17 + cw-sya-mon-001 IN A 10.130.0.43 \ No newline at end of file diff --git a/compose/playbooks/infra-base_admin.yml b/compose/playbooks/infra-base_admin.yml new file mode 100644 index 0000000..6e1809d --- /dev/null +++ b/compose/playbooks/infra-base_admin.yml @@ -0,0 +1,50 @@ +--- +# --------------------------- +# Добавление локальных администраторов +# --------------------------- +- hosts: all + become: yes + gather_facts: false + vars: + ansible_ssh_pipelining: "true" + ansible_user: "aantropov" + ansible_ssh_transfer_method: "piped" + ansible_ssh_common_args: "-o StrictHostKeyChecking=no" + ansible_port: 22 + users: + - { name: 'gem-admin', comment: 'Gem local administrator', exclusive: true, ssh_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCGF42ADoauvpQeNW9I3dBvra4+/aK3zz0y8moBKngdwLbg/yu5dYlB7p4w2qp3QEFcHatyBHrjezKOEO5qM7HFx2Yp0dsR7j25ZhLc8Oy85eFJIKRu4DTJLahNgp+ybL+zjadRVGuc6xQtFemOtFTNzeMhwxvgLF312/pWnVlN3KIoIbOxOwnp0hr1yvKivDRTmDUI3bNvgCLSnap5fxcBZZklz+AzshIH9rY0W86VCewACRnPRcaE94O+4XjibqYi8vQPGUAu9NpRAPvuDbp1N5BgwhLcDx/XdQDcyhMdtLbHJ/I1WhaTLJjUDXVp3wcC4E7jpzXLBqkwPneplpVHT2Qk5AGp0R8Vb+q4TMLRbgm00036CcXY1Y/6VtAd1c3+QlXMSVMDEHBMBJ/NBM8cKkPhhBT8C1Tt660IFRErx8C48IqpGfHjHQZn8Xf0RWIyZ28c/x6mOhHJqqFAsPCsGsYcWVdAZBD53tWHGdjYcLGeI3UCYBFnnj4fEvQUUnBE3JB1NdkeVxYElbh7SktVTh3G3kNFAwWYgwn31Qh74jWpN11H8m5XM0I3R2TGzi7yuS8zKOKaEZwObSNVTfBbPHh6uVK3olIsiznAsI19jqrg+QQjStaNhHDcN/SZTxboy7q7Rnigl2cJOHM2rxm8NmuMuTHdPKlpbigvq7PFMQ== gem-admin" } + - { name: 'lsokurov', comment: 'Leonid Sokurov', exclusive: true, ssh_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC99En90Q7+VECxJLvVJY4TjasnFxC77YHpEebNeJg8iWapjvFxQ5ROOQX43x0kRKIZrnj3aQmpSvs+RuvWAxszm3BE4jiSftL49ImSMdmyoiGV5l1WcV1HJrmwz7jq5Eq8P/iMw3hVkhWU6b860kWpAhFiaW/g58BHJHVYn4M+pLDWk2NRkvHD4Ez1rtH28hXqrrm+TD/KhxLUrqQdytvYi5trzWQbahtpOtev0Dyi8oBdj6Jph/pB3mzZnWFGP2r106x4bKlvzKlLgNn9yPgygknDIEmD9dIEf2sJ/WbxqurR0x+Id3rpAiyvZWnY0O4CNcP9DIOrM0onz2he+hJTH+Kr8tiJBfpqoboSnyIdPfh2dMGGpGxPYoghVBg6ylkQ6ZUB8xUTTjfzCxxNF7TgMI064iXi+RWwepknLxw2vcgiSRi/nnv9NFJta+QOskK+05YXecWcnJVvREmYkGSzKEkuzwxEWwYIc2/JAngQxeenGaBAl9mDKdFPyZcQUy0= leonisa@Leonids-MacBook-Pro.local"} + - { name: 'aantropov', comment: 'Aleksandr Antropov', exclusive: true, ssh_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC9dzp4d6A9ZfVOXmHdiSW05qZbCGWBm8W0+KTlqEaRssliHHmrWSntiSvoeG2nQPJKBA5MAi476T/hmT2ym1oZxvRdyBODRw/UdXboHTXejXivtfhVT0ghcKOrllDbwzM/J9PT4k7rdefduIpv0wGHXzIVFqU1ZdjqDVqixuPq8dVSJJIOI5am6AJ6Of+U87FNC91GlGEezq8+Xo55BvUTKPjxnoHWUKVvvT6ci78i8I7Ux1Dx48lj90J61z9BIxvDZbWDDUY9gL2E0TSsYYDws5uX/+OSi3BIzJvMdzcn5LUTjIKX5FLYhdpagwqX2vaziI3S51RSpsqC6w76awKmcNbKfZzn8bXsvbK6pnwGKhFYBYZKui2piqq8rZ5MEHabHmEf1EdCtVW5Q0FNZzBKRFy6Sa5FwdzJPCmdoVOCtwXVZtKgUGHksxtWpMuuvO5QcXDoOqyCtTnk79S1fOYfQWbtTeKOpHiIONCgl6/CzZdoB8FXYRuyLtXmRTQy7rM= antropov.a.b-2023-09-25" } +# - { name: 'ffesenko', comment: 'Filipp Fesenko', exclusive: true, ssh_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDP5mfMMJ8J/ZVC7QFYsbQ0lB9qc7zLNq41IgVCLi/f83GUcJ2OfXh7/SetGnujOnyIsM6qv3kaWmgrSKmaR/0AL7YcAXvKgFf/XThs6b/tOpKiaZIT2Yn3hW+yW7FcqO96tNSa3TMikSR/K72goC6jXvVFgbtREuwuMxnuDx4U5hJdsvx/fmMywCTPtiSWNXMJC1m08v9xaeaygycftVSPsJc8QeWThqt1Dvr39JcIZDqHbrdbqGzWzT2vJRbpmKkECoeW1d9wqr4DcsjamIKikS4/cw84pP8S0Sxu+JsK+H86v+gw9P6SfQYxVMwawjeQWukk2OK3MtKjpXiIF8f/5PJAq4QYo9aDgX3igoKvdFPni1qkn3NLhI+BexwkF1VCzalE4L9p75EkYpQzyhcAZ5HGF9FUVR1JNfdP+dgVCBjXgHcyKNGD9+MsUHx1BUeEFnon2P5XJ49FFXec3pZ+7Hrnf13EPGfz8ingoNvvV+2VNAUXpMpgB0/lba+vH68= f.fesenko" } +# - { name: 'mchudinov', comment: 'Maksim Chudinov', exclusive: true, ssh_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJt7pOgOb7P6INJqnUhLj+gOJS/oH7JrZc13tfIC2lzi mchudinov" } + + tasks: + - name: Add local admin + user: + comment: "{{ item.comment }}" + createhome: true + name: "{{ item.name }}" + shell: /bin/bash + password_lock: true + force: true + loop: + "{{ users }}" + no_log: true + - name: Add SSH keys + authorized_key: + user: "{{ item.name }}" + key: "{{ item.ssh_key }}" + exclusive: "{{ item.exclusive }}" + loop: + "{{ users }}" + no_log: true + + - name: Sudo permissions + community.general.sudoers: + name: "{{ item.name | lower | replace('.','_') }}-access" + user: "{{ item.name }}" + commands: ALL + nopassword: true + state: present + loop: + "{{ users }}" \ No newline at end of file diff --git a/compose/playbooks/infra-docker-registry.yml b/compose/playbooks/infra-docker-registry.yml new file mode 100644 index 0000000..2d8b3f3 --- /dev/null +++ b/compose/playbooks/infra-docker-registry.yml @@ -0,0 +1,8 @@ +--- +- name: infra-common + hosts: cw-sya-reg-001 + become: true + gather_facts: true + roles: + - { role: infra-common, tags: ["common"] } + - { role: infra-container-registry, tags: ["registry"] } \ No newline at end of file diff --git a/compose/playbooks/keycloak_server/README.md b/compose/playbooks/keycloak_server/README.md new file mode 100644 index 0000000..8cb64f7 --- /dev/null +++ b/compose/playbooks/keycloak_server/README.md @@ -0,0 +1,4 @@ +====================================================================== +Playbook information +====================================================================== +Плейбук по установке Keycloak в Docker \ No newline at end of file diff --git a/compose/playbooks/keycloak_server/ansible.cfg b/compose/playbooks/keycloak_server/ansible.cfg new file mode 100644 index 0000000..20d7065 --- /dev/null +++ b/compose/playbooks/keycloak_server/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +ansible_managed="Ansible managed" +host_key_checking=False +inventory=inventory/hosts diff --git a/compose/playbooks/keycloak_server/defaults/main.yml b/compose/playbooks/keycloak_server/defaults/main.yml new file mode 100644 index 0000000..11163dc --- /dev/null +++ b/compose/playbooks/keycloak_server/defaults/main.yml @@ -0,0 +1,9 @@ +--- +# defaults vars +# ansible_python_interpreter: "/usr/libexec/platform-python" +ansible_ssh_pipelining: "true" +ansible_user: "gem-admin" +ansible_ssh_transfer_method: "piped" +ansible_ssh_common_args: "-o StrictHostKeyChecking=no" +ansible_port: 22 + diff --git a/compose/playbooks/keycloak_server/handlers/main.yml b/compose/playbooks/keycloak_server/handlers/main.yml new file mode 100644 index 0000000..c09dec7 --- /dev/null +++ b/compose/playbooks/keycloak_server/handlers/main.yml @@ -0,0 +1,5 @@ +--- +# handlers file + + + diff --git a/compose/playbooks/keycloak_server/inventory/hosts b/compose/playbooks/keycloak_server/inventory/hosts new file mode 100644 index 0000000..7b87a1b --- /dev/null +++ b/compose/playbooks/keycloak_server/inventory/hosts @@ -0,0 +1,4 @@ + +[iam-host] +cw-sya-iam-001 ansible_host=10.130.0.41 + diff --git a/compose/playbooks/keycloak_server/main.yml b/compose/playbooks/keycloak_server/main.yml new file mode 100644 index 0000000..dd26998 --- /dev/null +++ b/compose/playbooks/keycloak_server/main.yml @@ -0,0 +1,18 @@ +--- +# Установка Keycloak (Docker) +- name: Install Keycloak (Docker) + hosts: cw-sya-iam-001 + gather_facts: true + become: true + vars_files: + - vars/base_conf.yml + - vars/secret.yml + - defaults/main.yml + pre_tasks: + - import_tasks: tasks/check_os_version.yml + roles: + - role: docker_install + when: ansible_distribution == "Ubuntu" and docker_install == "yes" + - role: keycloak_install_docker + when: ansible_distribution == "Ubuntu" + diff --git a/compose/playbooks/keycloak_server/roles/docker_install/README.md b/compose/playbooks/keycloak_server/roles/docker_install/README.md new file mode 100644 index 0000000..ae41738 --- /dev/null +++ b/compose/playbooks/keycloak_server/roles/docker_install/README.md @@ -0,0 +1,4 @@ +====================================================================== +Role information +====================================================================== +Установка Docker-ce и Docker-compose \ No newline at end of file diff --git a/compose/playbooks/keycloak_server/roles/docker_install/handlers/main.yml b/compose/playbooks/keycloak_server/roles/docker_install/handlers/main.yml new file mode 100644 index 0000000..7479ceb --- /dev/null +++ b/compose/playbooks/keycloak_server/roles/docker_install/handlers/main.yml @@ -0,0 +1,4 @@ +--- +# handlers file + + diff --git a/compose/playbooks/keycloak_server/roles/docker_install/tasks/configure_docker.yml b/compose/playbooks/keycloak_server/roles/docker_install/tasks/configure_docker.yml new file mode 100644 index 0000000..0aeb46c --- /dev/null +++ b/compose/playbooks/keycloak_server/roles/docker_install/tasks/configure_docker.yml @@ -0,0 +1,29 @@ +--- +# Настройка Docker +- name: Configure Docker + block: + - name: Make docker config + template: + src: daemon.json.j2 + dest: /etc/docker/daemon.json + mode: 0644 + register: docker_updated + + - name: Enable and start Docker service + service: + name: docker + state: started + enabled: yes + + - name: Restart Docker service + service: + name: docker + state: restarted + when: docker_updated['changed'] + + - name: Add users to a docker group + ansible.builtin.user: + name: "{{ item }}" + groups: docker + loop: "{{ docker_users_list }}" + # when: docker_users_list is defined \ No newline at end of file diff --git a/compose/playbooks/keycloak_server/roles/docker_install/tasks/install_docker.yml b/compose/playbooks/keycloak_server/roles/docker_install/tasks/install_docker.yml new file mode 100644 index 0000000..6cfefa7 --- /dev/null +++ b/compose/playbooks/keycloak_server/roles/docker_install/tasks/install_docker.yml @@ -0,0 +1,35 @@ +--- +# Установка Docker +- name: "Check packages is installed" + package_facts: + manager: "auto" + +- name: "Install Docker" + block: + - name: "Add GPG key" + shell: | + install -m 0755 -d /etc/apt/keyrings + curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc + chmod a+r /etc/apt/keyrings/docker.asc + + - name: "Add the repository to Apt sources" + shell: | + echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ + $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ + sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + apt-get update + + - name: Install docker packages + apt: + name: '{{ item }}' + state: present + update_cache: yes + loop: + - docker-ce + - docker-ce-cli + - containerd.io + - docker-buildx-plugin + - docker-compose-plugin + - docker-compose + when: "'docker-ce' not in ansible_facts.packages" \ No newline at end of file diff --git a/compose/playbooks/keycloak_server/roles/docker_install/tasks/main.yml b/compose/playbooks/keycloak_server/roles/docker_install/tasks/main.yml new file mode 100644 index 0000000..08fc61c --- /dev/null +++ b/compose/playbooks/keycloak_server/roles/docker_install/tasks/main.yml @@ -0,0 +1,9 @@ +--- + +# Установка Docker +- name: Install Docker + include_tasks: install_docker.yml + +# Настройка Docker +- name: Configure Docker + include_tasks: configure_docker.yml diff --git a/compose/playbooks/keycloak_server/roles/docker_install/templates/daemon.json.j2 b/compose/playbooks/keycloak_server/roles/docker_install/templates/daemon.json.j2 new file mode 100644 index 0000000..c8a6d5e --- /dev/null +++ b/compose/playbooks/keycloak_server/roles/docker_install/templates/daemon.json.j2 @@ -0,0 +1,7 @@ +{ + "log-driver": "json-file", + "log-opts": { + "max-size": "{{ docker_log_size }}", + "max-file": "{{ docker_log_files }}" + } +} \ No newline at end of file diff --git a/compose/playbooks/keycloak_server/roles/docker_install/vars/main.yml b/compose/playbooks/keycloak_server/roles/docker_install/vars/main.yml new file mode 100644 index 0000000..8831049 --- /dev/null +++ b/compose/playbooks/keycloak_server/roles/docker_install/vars/main.yml @@ -0,0 +1,7 @@ +--- +# vars file +docker_log_size: "100m" # Размер файла логов для Docker (в мегабайтах) +docker_log_files: "3" # Количество файлов логов для Docker +docker_users_list: # Пользователи которых необходлимо добавить в группу docker + - root + - gem-admin diff --git a/compose/playbooks/keycloak_server/roles/keycloak_install_docker/README.md b/compose/playbooks/keycloak_server/roles/keycloak_install_docker/README.md new file mode 100644 index 0000000..cbc8819 --- /dev/null +++ b/compose/playbooks/keycloak_server/roles/keycloak_install_docker/README.md @@ -0,0 +1,4 @@ +====================================================================== +Role information +====================================================================== +Установка Keycloak (Docker) \ No newline at end of file diff --git a/compose/playbooks/keycloak_server/roles/keycloak_install_docker/handlers/main.yml b/compose/playbooks/keycloak_server/roles/keycloak_install_docker/handlers/main.yml new file mode 100644 index 0000000..7479ceb --- /dev/null +++ b/compose/playbooks/keycloak_server/roles/keycloak_install_docker/handlers/main.yml @@ -0,0 +1,4 @@ +--- +# handlers file + + diff --git a/compose/playbooks/keycloak_server/roles/keycloak_install_docker/tasks/install_keycloak.yml b/compose/playbooks/keycloak_server/roles/keycloak_install_docker/tasks/install_keycloak.yml new file mode 100644 index 0000000..a8ffcde --- /dev/null +++ b/compose/playbooks/keycloak_server/roles/keycloak_install_docker/tasks/install_keycloak.yml @@ -0,0 +1,57 @@ +--- +# Установка Keycloak (Docker) +- name: Install Keycloak + block: + - name: Creates base directory + ansible.builtin.file: + path: /opt/docker/{{ item }} + state: directory + loop: + - keycloak + - keycloak/ssl + - keycloak/db + + - name: Create compose config + template: + src: compose.yml.j2 + dest: /opt/docker/keycloak/compose.yml + register: compose_updated + + - name: Copy SSL PEM key + copy: + content: "{{ iam_ssl_pem }}" + dest: "/opt/docker/keycloak/ssl/iam.pem" + mode: 0644 + register: cert_updated + + - name: Pull docker images + shell: | + cd /opt/docker/keycloak/ + docker compose pull + when: compose_updated['changed'] + + - name: Run docker compose config + shell: | + cd /opt/docker/keycloak/ + docker compose stop + docker compose up -d + when: compose_updated['changed'] or cert_updated['changed'] + + - name: Allow ports + community.general.ufw: + rule: allow + port: "{{ item }}" + proto: tcp + loop: + - 80 + - 443 + + - name: Check service ports + wait_for: + port: "{{ item }}" + host: 127.0.0.1 + state: started + timeout: 5 + delay: 3 + loop: + - 443 diff --git a/compose/playbooks/keycloak_server/roles/keycloak_install_docker/tasks/main.yml b/compose/playbooks/keycloak_server/roles/keycloak_install_docker/tasks/main.yml new file mode 100644 index 0000000..f6e361c --- /dev/null +++ b/compose/playbooks/keycloak_server/roles/keycloak_install_docker/tasks/main.yml @@ -0,0 +1,6 @@ +--- + +# Установка Keycloak +- name: Install Keycloak + include_tasks: install_keycloak.yml + diff --git a/compose/playbooks/keycloak_server/roles/keycloak_install_docker/templates/compose.yml.j2 b/compose/playbooks/keycloak_server/roles/keycloak_install_docker/templates/compose.yml.j2 new file mode 100644 index 0000000..52a0365 --- /dev/null +++ b/compose/playbooks/keycloak_server/roles/keycloak_install_docker/templates/compose.yml.j2 @@ -0,0 +1,44 @@ +services: + keycloak_web: + # image: quay.io/keycloak/keycloak:25.0.1 + image: quay.io/keycloak/keycloak:latest + container_name: keycloak_web + restart: always + environment: + KC_DB: postgres + KC_DB_URL: jdbc:postgresql://keycloakdb:5432/keycloak + KC_DB_USERNAME: {{ db_username }} + KC_DB_PASSWORD: {{ db_pass }} + + KC_HOSTNAME: {{ fqdn_name }} + KC_HOSTNAME_PORT: 8443 + KEYCLOAK_HTTPS_PORT: 8443 + KEYCLOAK_PRODUCTION: 'true' + KEYCLOAK_ENABLE_HTTPS: 'true' + KEYCLOAK_HTTPS_USE_PEM: 'true' + KC_HTTPS_CERTIFICATE_FILE: /etc/x509/https/iam.pem + KC_HTTPS_CERTIFICATE_KEY_FILE: /etc/x509/https/iam.pem + KC_LOG_LEVEL: info + KC_METRICS_ENABLED: 'true' + KC_HEALTH_ENABLED: 'true' + KEYCLOAK_ADMIN: {{ admin_username }} + KEYCLOAK_ADMIN_PASSWORD: {{ admin_pass }} + command: + - start + depends_on: + - keycloakdb + ports: + - 443:8443 + volumes: + - "/opt/docker/keycloak/ssl/:/etc/x509/https" + + keycloakdb: + image: postgres:16 + container_name: keycloakdb + restart: always + volumes: + - /opt/docker/keycloak/db/:/var/lib/postgresql/data + environment: + POSTGRES_DB: keycloak + POSTGRES_USER: {{ db_username }} + POSTGRES_PASSWORD: {{ db_pass }} \ No newline at end of file diff --git a/compose/playbooks/keycloak_server/roles/keycloak_install_docker/vars/main.yml b/compose/playbooks/keycloak_server/roles/keycloak_install_docker/vars/main.yml new file mode 100644 index 0000000..fa2fb4c --- /dev/null +++ b/compose/playbooks/keycloak_server/roles/keycloak_install_docker/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file diff --git a/compose/playbooks/keycloak_server/tasks/check_os_version.yml b/compose/playbooks/keycloak_server/tasks/check_os_version.yml new file mode 100644 index 0000000..2909c8b --- /dev/null +++ b/compose/playbooks/keycloak_server/tasks/check_os_version.yml @@ -0,0 +1,15 @@ +--- +# Проверка версии ОС +- name: Check OS version + block: + # - name: DEBUG OS version + # debug: + # msg: + # - "OS: {{ ansible_distribution }}" + # - "Version: {{ ansible_distribution_version }}" + # - "Major version: {{ ansible_distribution_major_version }}" + + - name: OS version not supported + fail: + msg: "Operating system {{ ansible_distribution }} ver. {{ ansible_distribution_major_version }} not supported" + when: ansible_distribution not in ['Ubuntu'] \ No newline at end of file diff --git a/compose/playbooks/keycloak_server/vars/base_conf.yml b/compose/playbooks/keycloak_server/vars/base_conf.yml new file mode 100644 index 0000000..3cf8409 --- /dev/null +++ b/compose/playbooks/keycloak_server/vars/base_conf.yml @@ -0,0 +1,5 @@ +--- +# Переменные конфигурации +docker_install: "yes" # Установка Docker - "yes" или "no" +fqdn_name: "iam.stage.co-work.local" # FQDN имя сервиса IAM + diff --git a/compose/playbooks/keycloak_server/vars/secret.yml b/compose/playbooks/keycloak_server/vars/secret.yml new file mode 100644 index 0000000..22ccfdb --- /dev/null +++ b/compose/playbooks/keycloak_server/vars/secret.yml @@ -0,0 +1,189 @@ +$ANSIBLE_VAULT;1.1;AES256 +32333836633564653231393966383764633834663564316138626464666438656636636261633263 +3165303136353232623535326338363936306138336232340a613161356461353764326231613934 +30333933386631373238333865386437343935643666336366613233343931323434393831323230 +6264303839653264300a336335643533333364646433353335313733623031313137343862663136 +30386362373564366338306139613632656566623265333361666436376264303663313664323433 +30663734623763343564393962663831373838623033636636636163383637393330323132303834 +62306231393465366663643433623430336339656166323037383364343632633632626262643937 +64646134613136346134386333666362393465383234636363336365613936646336356634643333 +38663064366364333631316162353837346637646230323565316339386237653765613862663138 +66336338333266363634303039313930323234366339373538333734316336363632643761613734 +31636438613835343631636564656137613833383865393830316331383933653336326132353131 +30373466356134366631343236333963393332666262396262636561396638346135326333333264 +36316333643430396138373733396437376232643864613066386332663339626466393336393561 +34646138326365356636646438356464333331363839643832333163306465623131373237393138 +34643535343033316532653938326563323466636534643034326637363431313532313535383265 +33646230626566393763633533316265346130633464623933343335613233343965363535643237 +35373839663535396462306164623365366666663733366464613863333961376639346436643037 +39383731303833653138333962333530306661356234643566316336383061396431366564623766 +31303762373035353737323463346334396265343365616138636665333261363662636235343363 +31626565386265313764666633396162346162376232343139396530663038643831346337333238 +31313661393930393330656435363837396366373732363531323163383864346634356230333663 +64313161643037333735316332633831613533653164346464633261646361626166623163373038 +64393465363331373639366465666363303031333864303364643239623463656634346636633432 +37336261663539366462346663373633326332336632306637383732623035333633656262393032 +39616138663463353066616534366163363036393064643536336266613433303964613866613239 +35633938356365646539366165613333323661333338646235363131383236343163393562316532 +61623531666266313439343934626663363838623963383238393862653162323866353932336664 +39653431356334663236613037323234636135313063343335316164343834336133633735373434 +36656163616430333161643336343964313238323333363737313836386366656332646465376166 +30383233666466313261616236343566386134356130336132646133343566343566653734343038 +35646134613362666232313366313533396535643163616432333861346232613830316239613166 +32323866306236323565626162613763313034656463333236663562326133393261383936616538 +31626630613133363666636238343164323434646163363562303333383965653263383332643064 +63333833636330656331316538663237303432643031316465663331303561666565313565653164 +34613739386434656231303562386264613663313561666162303436313363373739626537353366 +64353866313934376161333765313662303865383035366666326666303939343761343936366530 +62373537353531643766346164623236353463343263363862306134393864613264316265626262 +39343133363263313732623837663266636265303661643265623938306235363933316566313434 +63313832353434323732643635646138386638373932663533636163373033623462306437663237 +65343638343933623665626634393238623437633065633064363333363465373761663939633730 +35383539646432316233636563316332383139346637383037393662653037313937393839623966 +61333635303436666532323063666365616261316535343063663730653637636132373561333834 +62653064333934613935343831633062616532386130616537616438366233373863613263333665 +36353037623532643730343361366266653165313231626134373733383538326436353366656330 +66346531613965383732316634396461633437656630393733393339393564396239663062626263 +62613761636531346266306261393166373732373939663162643261353630366235623362316435 +61643130636137666230373031383631323030393262343863666137623233333165643965326432 +61613264303065616565336465663164616332363335636631393563316137643636333263386237 +37383934636133633964386134616237623064653034353662383035653330323662373466663936 +66663030326233306339346165616636366432343139613965323131653037313835353136363466 +31633731336439323336393630356332626133643861336238393932323465643262633230636537 +32636336373465633364353764393762363965336364646263303136373931653661313339333631 +64623830336262663631316131333762333563656666343866656237363066643336356366613030 +66336339663166343230366333393436346337333833333132383630383037373530666661326539 +38643030653861633737636565663063663131343830373032616562666166346530333630656431 +36343264653138393038643338616364633431636534656263666339303631633838643562653534 +66373861303965643836313039623732393263616430306332386233643238626336316637393038 +30336535653963366433393534313933313266393062346461663133613461356233343738343333 +30643037343631326435303230343133326130373965616461613735303564663637333531666432 +61323039303633623663303264643932326362366263353232333333383266663531356530303430 +64653564386663326532373363653065376663643339653561376163326639613664646239336661 +31333532643737343037623036343263313039366137393063326330316266643836633164633032 +64376134653838313364316663363939663161626262373630373238373537363436363437656130 +33626635313730383734303536316130626432313337373631653636653239353430333161333263 +30653936373232613939363431396366646438393835626130626365303064333261333766646633 +62663763333665373230313163633037393662366432326537343866613936646534313263616134 +38363062356666343537666664303035616461626639306561393339303432656163393366613965 +62313135366466396466633061346333303165363237353466383835643335383966333066343866 +31316433646331356364346664643734373432313537383236646465656661383030363335343236 +64336236306561326334663035386338613463326239356133303233316139613633326336633262 +30623134616332656538386437353661373461663634306436383534666333623339353837383334 +36373233643864653433326134313431313331383936376432353734663833646639616565303631 +36343661303562346633383362326236613937343437393239326235383366623763636630313339 +66343462363232306430326263393838333238636439616461363731386234376333366638376530 +30626333333936613339643931626637323134363230313564633962653964316234323733333035 +39363936396561636330343836643163303732313934373836326261376330323834643966633436 +63373634353838663036343065366561616135376534313037613736653564623332386362646437 +34663139356636646133313164316538396435353638396336313738663162646234356333653162 +37336461666362383863366361333362303762383862646330613734366433666235316530633734 +37383663376561666233353536393534383235623665366332306466363936363634613634396631 +65663739636631643564636463613162303166633962333931633664333735363465623235313438 +66376563326431386661346163633534613232633536636137373731653234336262363133353964 +65313832376532626366303463626562323234353664626565346163353033396234363761313135 +33663366386463333732303362633534363338316363316334623333393534343633386237363561 +62613136663831393530366261623239343330653766623830333061616130333231656339633365 +63346231383533646663366536336633633763383163656135623234343265393337323461623764 +61343333383738613564653563356238623061633538346564643932663734313832343039653433 +32613931646165636266623065646562386332383663623339366435646332313438356463636164 +32656234393433343661383137346132396632616437323064343731316331353732303366303433 +34333337626466343664363635656434316533303863613861333662313530323131623937393739 +66333931316635393161656137613666343763643965346364323063386637306630313863386661 +62386561653961393936346337353861333435646363343638626264613537383537613637396632 +62373463383662346139633435626161353237323138353663316465613563363261396539353965 +38313031666333366230306436396535306566616265336236643734636361663164613066303466 +37643039386362613033323139373133363238306665616338653736633030343535326437373265 +36656339313233363931303766313263666237336230616262623865656634393333383334393332 +32323033373333356234396238336138373661643238306539336463626134363035333239306139 +36613938646633393237313962343166366563326438356136313235363231663830633861653433 +63396630393338356430373563613262653039313339343161336635666461323061613961383039 +62363766633333306233383035663731363362656535623734656430663465363336666565663332 +31623432643063303332326536393338666536663334366232383838613732633833333466643361 +39313537316331343733613436356234626634373639383263386162623337396365383439323032 +31303935613533306537393963373663313531306533313537373464656366646132656432633063 +39633232643134313334616430613639633739313332643633613362343139353736666230373332 +33633563343035303634363836326232636137656337346335396238313766643038623164656134 +32323566626235653738643062653439396537666563376230343364636439393464306538323630 +65616131373330643331636637343262346239333032643332343766623938643739393530666164 +39356236396561303033393033393663336532366661383162383433333665363961313132323664 +39366630316161663066363666333934376530343766663665623037366339666263306665383535 +64616132613561383836646333386439643962613064656537323730333034393661306662323733 +34636465613263613031333131633833333030663262313761333063383231373966313237623264 +65323631373434366337643463323264326237663539303338336465396532313032393765346239 +61663535363562663364323136353235666563343937666333376265373166653830393462643530 +31633531326135363238663763363562613337633137306137626334353661616333316635656538 +64373937626538363331383838643564646463316462363638653133363561643034333532303862 +34313636646636363964366662316435613231316137313534623035623730666635343732383966 +33353465376236363136353933353638363536353832386664653636663638343566643963666532 +31326535373365343332303865386461666465366632663535303466366261303335333134373133 +66363431396636383837653466643635323836346361346561653962336130353536363261313034 +64383936356436396238653666303831636330316333613461633631626162613630613363346637 +65306665353033646137363338363737613531313432353066316663636533386339313162356536 +35306262353664333533386366623364373635376363653031626334303137316263326363343861 +37366561343164623533323363386439616533663731396331636362623730343632393238663364 +34376236313738326439383633306532343532366237373263376664316437336261356639373065 +30346130616334633566343733663532356137313566646537353431613730613065633033393534 +65323530663036613035336335623337366464343537303737656534646366346331356666363532 +33313965633135346236346135643730353236376331626436613933386464623762393739366232 +32663864663064633563643931653339623262353036376634333531656564653038666531386161 +30646136326230663066316630383938393332663762383434623738386239633636333761643431 +61616364626335323563393037396563636632633639633762366363386662363130313137653434 +35356534343631363733633539393935653334663931396364303137376139313130333830663538 +64356266636431626430336662333730393133326635396233663365356666366430623232346438 +62313263303762636663373937343465383936666533623635386332306462643835653432306130 +37323765663634373865643138633632316633376136353035663733623939336462373038376261 +34663832333335353233616630306137636561323435656137333131336137303461656337666339 +35303238353831646663363066653165623933613064383735626432396437663839613637333732 +36653063643538613132336263616131366334626235366435666135343264353866313263316361 +65666436356337306332613066316133633463653762333839393130343533353238613364653133 +30383233666339313538663638303936303461663439643366373933343563376233626135316263 +37393930663937616334303364383332616637386162323336313938333530663638316661623730 +65636235323230323030636266396230303636323739626164633436353035643032386232336330 +37633761313663343637646439386336333436313866393664393761363035646331306164343962 +65383038636265333764666635386533336563323434383562343430613436343332643666353633 +32346233363065353139633564626138343938333131316336636539623539623435613031303663 +33613336343162616137323238343464636433356236653362376431323438653137363666366533 +31633565633762643163653830386235306162323663636363343033303261613263363832393866 +31366133343362323231613238376537643163316437333661353264363739303830386233373665 +33313634636464313564333534336335363236643835386564633464336462616335663636383631 +33373035613634663331313230613737366662613033383363623932653262333931393134656666 +64633933653536666637666265306439343834353361396665363637656433386236333861303562 +35613766313965653066313238656535333235353331326431353234366164643432623133666430 +61346637363836643765633737636536306337383131643564363463303965656638316236333665 +37643934333132393834663931616236313730316139653231376237343537336438376334323861 +64373131383931633336643461663830663964356365653934306430396238323939666464393464 +62396336353562353431396265326131646266323864396332616463613032333235343836366337 +65643531353636626539653436356437623738643438633036633237323531383662316166383466 +35663866396366626233333132356339356165366663313665313966613364336339376538633665 +65646665366335383066316630366336336163313232633931363839303639316535353338323037 +66633236623234363633653062393564373331346232633665626230326332313937353035343032 +64633538383638353563363939346166613961346162393766323632376436376632323239363536 +64333466313063383061623463346563343837316563623338643139633963633661336438396462 +33353730646138313866656133323335386136333738616437353031663832313165653236353630 +35353363383666633238343862373963373962656435363332656261313939623939613234316330 +34336432626334663330643339636132653666333235363163356132623834373761363265376161 +39643430376532303234346664396639663566383338633938393965653461326365656365303833 +32306330336537333038353037643830353766363333383864653937316438643438376531633639 +62623563323234343334306230633833303866646637623638363539613839656265633434633133 +38633461666663613662623239373134616566316437623535323039363831626663633261376132 +35396561376361303062656564663862353636343266313862393961353763623064643333356463 +35383762636231643430376662393136613064663931343334666135666535343935313936393634 +30396637333031333765373965333631646332663331396337376432653062656266313938393461 +37613933623463666131393863376438393437616632613637383734313938646232653065643634 +64633964633264626530666561343130383038376133373431393930353731616634623639356637 +39663931376139323839643762346536346461303166396235386536616430646237656632613162 +35333033383664393032343733626665653937316264343333386234323564616330343231363065 +66366332613439356665633166616365353835613536396134373333386365376664333263653364 +33623536656438356463333266626166653830386265326134363633626530306632373835373237 +31366430643030336138336164663630393738653432366530626466326335623431313137383064 +32373931333764353861666262616437363966393032643030656134393638326335393331386631 +66616532336330616263323637396133663362396430653334333666653164353532626335383738 +34643964356236656635396231383531643661313762643666363264363738373832653932303333 +61326531396131666433383461363130336562653863356164323734323963303331636265623563 +30356464613333663061343830653738633765393061393065623261343866663866623465346130 +38356265313336646630386439663561323938643538336130303430323235656539303561366133 +64623261646461353237373336343132386336343766666565393737613736666537383831616233 +66343631383764383363623064653439326365323161313633633635353332363834393332303930 +61373137626362623033323463633866623661613931323339643166336337623337383537653666 +64663834373836626361 diff --git a/compose/playbooks/openldap_server/README.md b/compose/playbooks/openldap_server/README.md new file mode 100644 index 0000000..cb4b52f --- /dev/null +++ b/compose/playbooks/openldap_server/README.md @@ -0,0 +1,4 @@ +====================================================================== +Playbook information +====================================================================== +Плейбук по установке OpenLDAP в Docker \ No newline at end of file diff --git a/compose/playbooks/openldap_server/ansible.cfg b/compose/playbooks/openldap_server/ansible.cfg new file mode 100644 index 0000000..20d7065 --- /dev/null +++ b/compose/playbooks/openldap_server/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +ansible_managed="Ansible managed" +host_key_checking=False +inventory=inventory/hosts diff --git a/compose/playbooks/openldap_server/defaults/main.yml b/compose/playbooks/openldap_server/defaults/main.yml new file mode 100644 index 0000000..11163dc --- /dev/null +++ b/compose/playbooks/openldap_server/defaults/main.yml @@ -0,0 +1,9 @@ +--- +# defaults vars +# ansible_python_interpreter: "/usr/libexec/platform-python" +ansible_ssh_pipelining: "true" +ansible_user: "gem-admin" +ansible_ssh_transfer_method: "piped" +ansible_ssh_common_args: "-o StrictHostKeyChecking=no" +ansible_port: 22 + diff --git a/compose/playbooks/openldap_server/handlers/main.yml b/compose/playbooks/openldap_server/handlers/main.yml new file mode 100644 index 0000000..c09dec7 --- /dev/null +++ b/compose/playbooks/openldap_server/handlers/main.yml @@ -0,0 +1,5 @@ +--- +# handlers file + + + diff --git a/compose/playbooks/openldap_server/inventory/hosts b/compose/playbooks/openldap_server/inventory/hosts new file mode 100644 index 0000000..86de6b1 --- /dev/null +++ b/compose/playbooks/openldap_server/inventory/hosts @@ -0,0 +1,4 @@ + +[ldap-host] +cw-sya-ldap-001 ansible_host=10.130.0.16 + diff --git a/compose/playbooks/openldap_server/main.yml b/compose/playbooks/openldap_server/main.yml new file mode 100644 index 0000000..bb1d42d --- /dev/null +++ b/compose/playbooks/openldap_server/main.yml @@ -0,0 +1,18 @@ +--- +# Установка OpenLDAP (Docker) +- name: Install OpenLDAP (Docker) + hosts: cw-sya-ldap-001 + gather_facts: true + become: true + vars_files: + - vars/base_conf.yml + - vars/secret.yml + - defaults/main.yml + pre_tasks: + - import_tasks: tasks/check_os_version.yml + roles: + - role: docker_install + when: ansible_distribution == "Ubuntu" and docker_install == "yes" + - role: openldap_install_docker + when: ansible_distribution == "Ubuntu" + diff --git a/compose/playbooks/openldap_server/roles/docker_install/README.md b/compose/playbooks/openldap_server/roles/docker_install/README.md new file mode 100644 index 0000000..ae41738 --- /dev/null +++ b/compose/playbooks/openldap_server/roles/docker_install/README.md @@ -0,0 +1,4 @@ +====================================================================== +Role information +====================================================================== +Установка Docker-ce и Docker-compose \ No newline at end of file diff --git a/compose/playbooks/openldap_server/roles/docker_install/handlers/main.yml b/compose/playbooks/openldap_server/roles/docker_install/handlers/main.yml new file mode 100644 index 0000000..7479ceb --- /dev/null +++ b/compose/playbooks/openldap_server/roles/docker_install/handlers/main.yml @@ -0,0 +1,4 @@ +--- +# handlers file + + diff --git a/compose/playbooks/openldap_server/roles/docker_install/tasks/configure_docker.yml b/compose/playbooks/openldap_server/roles/docker_install/tasks/configure_docker.yml new file mode 100644 index 0000000..0aeb46c --- /dev/null +++ b/compose/playbooks/openldap_server/roles/docker_install/tasks/configure_docker.yml @@ -0,0 +1,29 @@ +--- +# Настройка Docker +- name: Configure Docker + block: + - name: Make docker config + template: + src: daemon.json.j2 + dest: /etc/docker/daemon.json + mode: 0644 + register: docker_updated + + - name: Enable and start Docker service + service: + name: docker + state: started + enabled: yes + + - name: Restart Docker service + service: + name: docker + state: restarted + when: docker_updated['changed'] + + - name: Add users to a docker group + ansible.builtin.user: + name: "{{ item }}" + groups: docker + loop: "{{ docker_users_list }}" + # when: docker_users_list is defined \ No newline at end of file diff --git a/compose/playbooks/openldap_server/roles/docker_install/tasks/install_docker.yml b/compose/playbooks/openldap_server/roles/docker_install/tasks/install_docker.yml new file mode 100644 index 0000000..6cfefa7 --- /dev/null +++ b/compose/playbooks/openldap_server/roles/docker_install/tasks/install_docker.yml @@ -0,0 +1,35 @@ +--- +# Установка Docker +- name: "Check packages is installed" + package_facts: + manager: "auto" + +- name: "Install Docker" + block: + - name: "Add GPG key" + shell: | + install -m 0755 -d /etc/apt/keyrings + curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc + chmod a+r /etc/apt/keyrings/docker.asc + + - name: "Add the repository to Apt sources" + shell: | + echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ + $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ + sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + apt-get update + + - name: Install docker packages + apt: + name: '{{ item }}' + state: present + update_cache: yes + loop: + - docker-ce + - docker-ce-cli + - containerd.io + - docker-buildx-plugin + - docker-compose-plugin + - docker-compose + when: "'docker-ce' not in ansible_facts.packages" \ No newline at end of file diff --git a/compose/playbooks/openldap_server/roles/docker_install/tasks/main.yml b/compose/playbooks/openldap_server/roles/docker_install/tasks/main.yml new file mode 100644 index 0000000..08fc61c --- /dev/null +++ b/compose/playbooks/openldap_server/roles/docker_install/tasks/main.yml @@ -0,0 +1,9 @@ +--- + +# Установка Docker +- name: Install Docker + include_tasks: install_docker.yml + +# Настройка Docker +- name: Configure Docker + include_tasks: configure_docker.yml diff --git a/compose/playbooks/openldap_server/roles/docker_install/templates/daemon.json.j2 b/compose/playbooks/openldap_server/roles/docker_install/templates/daemon.json.j2 new file mode 100644 index 0000000..c8a6d5e --- /dev/null +++ b/compose/playbooks/openldap_server/roles/docker_install/templates/daemon.json.j2 @@ -0,0 +1,7 @@ +{ + "log-driver": "json-file", + "log-opts": { + "max-size": "{{ docker_log_size }}", + "max-file": "{{ docker_log_files }}" + } +} \ No newline at end of file diff --git a/compose/playbooks/openldap_server/roles/docker_install/vars/main.yml b/compose/playbooks/openldap_server/roles/docker_install/vars/main.yml new file mode 100644 index 0000000..8831049 --- /dev/null +++ b/compose/playbooks/openldap_server/roles/docker_install/vars/main.yml @@ -0,0 +1,7 @@ +--- +# vars file +docker_log_size: "100m" # Размер файла логов для Docker (в мегабайтах) +docker_log_files: "3" # Количество файлов логов для Docker +docker_users_list: # Пользователи которых необходлимо добавить в группу docker + - root + - gem-admin diff --git a/compose/playbooks/openldap_server/roles/openldap_install_docker/README.md b/compose/playbooks/openldap_server/roles/openldap_install_docker/README.md new file mode 100644 index 0000000..e79e494 --- /dev/null +++ b/compose/playbooks/openldap_server/roles/openldap_install_docker/README.md @@ -0,0 +1,4 @@ +====================================================================== +Role information +====================================================================== +Установка Openldap (Docker) \ No newline at end of file diff --git a/compose/playbooks/openldap_server/roles/openldap_install_docker/files/cert/RootCA.crt b/compose/playbooks/openldap_server/roles/openldap_install_docker/files/cert/RootCA.crt new file mode 100644 index 0000000..d61df84 --- /dev/null +++ b/compose/playbooks/openldap_server/roles/openldap_install_docker/files/cert/RootCA.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIUTTdDE08O+Sdo6Zxp5pfPzJ6XFdMwDQYJKoZIhvcNAQEL +BQAwWTELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9z +Y293MRAwDgYDVQQKDAdjby13b3JrMRYwFAYDVQQDDA1jby13b3JrLmxvY2FsMB4X +DTI1MDEyNDEzMTAyOVoXDTM1MDEyMjEzMTAyOVowWTELMAkGA1UEBhMCUlUxDzAN +BgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MRAwDgYDVQQKDAdjby13b3Jr +MRYwFAYDVQQDDA1jby13b3JrLmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEArHKBcveZBhMwhifgiPn+bBU9hw3sLRI/SHFFMX3hNvjYFwpjY3Kv +g52jdbFdQwcG14/uiXJCkF3NX8iIpCtZx8aPHY2JKpzr9Kvs4Ui1c9f33Z+CEWOx +KaYcbz5L9f8EgDyAJcZ7dDBGv7n1MY4E9gTDUO1CBcSNhzcNRj4h0y3av0Q5wNew +1aGg0GN+BoniclX2silaGYx+UfsvdnQM0ujIA8RbtYsRyg0z2/6u80AeE0y5dBkH +JxLao6xs/Ha7xBmK0dUzovbFj1khskIET16xnMhsCImIDSQtfjOEPO44Lt9RtS/c +pd1AleNxG8DAGGIJ87FfsRTIsCuP0ZV5LwIDAQABo1MwUTAdBgNVHQ4EFgQUw1pz +/FfPI4ZswcAaX1SlU3Vyy38wHwYDVR0jBBgwFoAUw1pz/FfPI4ZswcAaX1SlU3Vy +y38wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAmrv6hpGTJAMY +WjlvJRlGVuTCmnEgLwkuOyFl+V5WIr6JRE14Mr56OVmXBrRD7ZnFSYX3BdG7Lan9 +AlQwsqPQRmd1jRW3FtOYRKOX5Bxti0JJBIZ8GdisBCWXeb0ijppyOT8Hs6JzFdac +1WhgJNx4lPZ/NgTSRXOshDVGSNNnU02IM/bz/8aW+Xi0jk6TMoiFju/49nXt3vs/ +Nr4UCmL/1SBsPrz0H8qgSz0Cbo8RkAVMkHitkWEsSMfaIR9Q9xY8JOUvAGb0TH/t +pPLF4WyNTqWsccLm5RluJugtPmT5ZzTYsfmaPulnSa8NqIcxD4lJvCU3OpL+eop6 +BHFEdJ5o3w== +-----END CERTIFICATE----- diff --git a/compose/playbooks/openldap_server/roles/openldap_install_docker/handlers/main.yml b/compose/playbooks/openldap_server/roles/openldap_install_docker/handlers/main.yml new file mode 100644 index 0000000..7479ceb --- /dev/null +++ b/compose/playbooks/openldap_server/roles/openldap_install_docker/handlers/main.yml @@ -0,0 +1,4 @@ +--- +# handlers file + + diff --git a/compose/playbooks/openldap_server/roles/openldap_install_docker/tasks/install_openldap.yml b/compose/playbooks/openldap_server/roles/openldap_install_docker/tasks/install_openldap.yml new file mode 100644 index 0000000..c2e19d7 --- /dev/null +++ b/compose/playbooks/openldap_server/roles/openldap_install_docker/tasks/install_openldap.yml @@ -0,0 +1,78 @@ +--- +# Установка OpenLDAP (Docker) +- name: Install OpenLDAP + block: + - name: Creates base directory + ansible.builtin.file: + path: /opt/docker/{{ item }} + state: directory + loop: + - openldap + - openldap/data + - openldap/data/certs + - openldap/data/ldap + - openldap/data/config + - openldap/haproxy + - openldap/haproxy/ssl + - openldap/haproxy/conf + + - name: Create compose config + template: + src: compose.yml.j2 + dest: /opt/docker/openldap/compose.yml + register: compose_updated + + - name: Create haproxy config + template: + src: haproxy.cfg.j2 + dest: /opt/docker/openldap/haproxy/conf/haproxy.cfg + register: haproxy_updated + + - name: Import CA certs + copy: + src: "cert/{{ item }}" + dest: "/opt/docker/openldap/data/certs/RootCA.crt" + loop: + - RootCA.crt + register: ca_cert_updated + + - name: Copy SSL private key + copy: + content: "{{ ldap_ssl_private_key }}" + dest: "/opt/docker/openldap/data/certs/ldap.key" + mode: 0600 + + - name: Copy SSL public key + copy: + content: "{{ ldap_ssl_public_key }}" + dest: "/opt/docker/openldap/data/certs/ldap.crt" + mode: 0600 + + - name: Copy PEM certificate for haproxy + shell: | + cat /opt/docker/openldap/data/certs/ldap.key /opt/docker/openldap/data/certs/ldap.crt > /opt/docker/openldap/haproxy/ssl/ldap.pem + + - name: Pull docker images + shell: | + cd /opt/docker/openldap/ + docker compose pull + when: compose_updated['changed'] + + - name: Run docker compose config + shell: | + cd /opt/docker/openldap/ + docker compose stop + docker compose up -d + when: compose_updated['changed'] or haproxy_updated['changed'] + + - name: Allow ports + community.general.ufw: + rule: allow + port: "{{ item }}" + proto: tcp + loop: + - 80 + - 443 + - 389 + - 636 + diff --git a/compose/playbooks/openldap_server/roles/openldap_install_docker/tasks/main.yml b/compose/playbooks/openldap_server/roles/openldap_install_docker/tasks/main.yml new file mode 100644 index 0000000..9f76594 --- /dev/null +++ b/compose/playbooks/openldap_server/roles/openldap_install_docker/tasks/main.yml @@ -0,0 +1,6 @@ +--- + +# Установка OpenLDAP +- name: Install OpenLDAP + include_tasks: install_openldap.yml + diff --git a/compose/playbooks/openldap_server/roles/openldap_install_docker/templates/compose.yml.j2 b/compose/playbooks/openldap_server/roles/openldap_install_docker/templates/compose.yml.j2 new file mode 100644 index 0000000..ab918f6 --- /dev/null +++ b/compose/playbooks/openldap_server/roles/openldap_install_docker/templates/compose.yml.j2 @@ -0,0 +1,61 @@ +services: + openldap: + image: osixia/openldap:latest + container_name: openldap + hostname: openldap + restart: "always" + ports: + - "389:389" + - "636:636" + volumes: + - ./data/certs:/container/service/slapd/assets/certs + - ./data/ldap:/var/lib/ldap + - ./data/config:/etc/ldap/slapd.d + environment: + - LDAP_ORGANISATION={{ domain_lvl_2 }} + - LDAP_DOMAIN={{ domain_lvl_2 }}.{{ domain_lvl_1 }} + - LDAP_ADMIN_USERNAME= {{ admin_username }} + - LDAP_ADMIN_PASSWORD={{ admin_pass }} + - LDAP_CONFIG_PASSWORD={{ config_pass }} + - "LDAP_BASE_DN=dc={{ domain_lvl_2 }},dc={{ domain_lvl_1 }}" + - LDAP_TLS_CRT_FILENAME=ldap.crt + - LDAP_TLS_KEY_FILENAME=ldap.key + - LDAP_TLS_CA_CRT_FILENAME=RootCA.crt + - LDAP_READONLY_USER=true + - LDAP_READONLY_USER_USERNAME={{ ro_username }} + - LDAP_READONLY_USER_PASSWORD={{ ro_pass }} + networks: + - openldap + + phpldapadmin: + image: osixia/phpldapadmin:latest + container_name: phpldapadmin + hostname: phpldapadmin + restart: "always" + ports: + - "80:80" + environment: + - PHPLDAPADMIN_LDAP_HOSTS=openldap + - PHPLDAPADMIN_TRUST_PROXY_SSL=true + - PHPLDAPADMIN_HTTPS=false + depends_on: + - openldap + networks: + - openldap + + haproxy: + image: haproxy:2.3 + container_name: haproxy + ports: + - 443:443 + volumes: + - ./haproxy/conf/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro + - ./haproxy/ssl:/usr/local/etc/ssl:ro + networks: + - openldap + depends_on: + - phpldapadmin + +networks: + openldap: + driver: bridge \ No newline at end of file diff --git a/compose/playbooks/openldap_server/roles/openldap_install_docker/templates/haproxy.cfg.j2 b/compose/playbooks/openldap_server/roles/openldap_install_docker/templates/haproxy.cfg.j2 new file mode 100644 index 0000000..f5ceb53 --- /dev/null +++ b/compose/playbooks/openldap_server/roles/openldap_install_docker/templates/haproxy.cfg.j2 @@ -0,0 +1,23 @@ +defaults + mode http + timeout connect 5s + timeout client 5s + timeout server 5s + +frontend ldap + mode http +# bind :80 + bind :443 ssl crt /usr/local/etc/ssl/ldap.pem + http-response set-header Cache-Control no-cache + option http-keep-alive + redirect scheme https if !{ ssl_fc } + option forwardfor + default_backend ldap + +backend ldap + mode http + http-reuse safe + option http-keep-alive + option forwardfor + default-server inter 5s fall 3 rise 3 + server srv-phpldapadmin phpldapadmin:80 check diff --git a/compose/playbooks/openldap_server/roles/openldap_install_docker/vars/main.yml b/compose/playbooks/openldap_server/roles/openldap_install_docker/vars/main.yml new file mode 100644 index 0000000..fa2fb4c --- /dev/null +++ b/compose/playbooks/openldap_server/roles/openldap_install_docker/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file diff --git a/compose/playbooks/openldap_server/tasks/check_os_version.yml b/compose/playbooks/openldap_server/tasks/check_os_version.yml new file mode 100644 index 0000000..2909c8b --- /dev/null +++ b/compose/playbooks/openldap_server/tasks/check_os_version.yml @@ -0,0 +1,15 @@ +--- +# Проверка версии ОС +- name: Check OS version + block: + # - name: DEBUG OS version + # debug: + # msg: + # - "OS: {{ ansible_distribution }}" + # - "Version: {{ ansible_distribution_version }}" + # - "Major version: {{ ansible_distribution_major_version }}" + + - name: OS version not supported + fail: + msg: "Operating system {{ ansible_distribution }} ver. {{ ansible_distribution_major_version }} not supported" + when: ansible_distribution not in ['Ubuntu'] \ No newline at end of file diff --git a/compose/playbooks/openldap_server/vars/base_conf.yml b/compose/playbooks/openldap_server/vars/base_conf.yml new file mode 100644 index 0000000..1e9a83d --- /dev/null +++ b/compose/playbooks/openldap_server/vars/base_conf.yml @@ -0,0 +1,6 @@ +--- +# Переменные конфигурации +docker_install: "yes" # Установка Docker - "yes" или "no" +domain_lvl_2: "co-work" # Имя домена на втором уровне +domain_lvl_1: "ru" # Имя домена на первом уровне + diff --git a/compose/playbooks/openldap_server/vars/secret.yml b/compose/playbooks/openldap_server/vars/secret.yml new file mode 100644 index 0000000..4d900d6 --- /dev/null +++ b/compose/playbooks/openldap_server/vars/secret.yml @@ -0,0 +1,198 @@ +$ANSIBLE_VAULT;1.1;AES256 +31333535313130303139323133653730663365333730363436306433633330363935306461663730 +3638396433336239363836643934313331393433626537320a353334336237323838346136363561 +35326532353766336535393464303239613336323264633333323032353738333231363034323638 +3530323466623230640a623736336461623634646164313831316231376234353239363730386131 +35306565306639326437393932656636363837323534386435613162656334663766636563616662 +33663239653931613266343136306337346639643765623833626235356638366538336566313233 +38653866386666623365356237616361366463656365333735623731376334326438373662653763 +34326337623563356130366630383763663639646238643834613964373965653031326361323366 +34663331343930373964316533633337633835363333343731623465643535303762336538386134 +35663065306662643734356364656237346637666663363333303066396330356637363931383138 +35666535636265343130386533323937393832646131303832376266333865616335306430616638 +30656161393363343165386263626365626239626138633162346466363530393435646163373132 +33613135633635373332626266363835356638386238313738366365333735643833323161303037 +63386664666437666132346665396333326633613564346636323630613461393334653261373335 +39303034643636633939343533656337656166333232333663633632373936346237313434663964 +61616634613366343834633863636361383365343137626237363439343038333131323665373236 +63633735376665656463383333633733623633666262326663663039366535363532303837646463 +37393661383035386430373238663737633565353531346137623438633431646363636636363730 +63386461373438613934363335306330386239303637613738353238396362643763623230643238 +64333231646530393138613331393466343137633131346432623336303066353162663134373962 +64663639323864336539333532346366373436633237333938353630373239643332353630633465 +38316538626430303637346566353731613062373334323465353539636431303431623463333966 +31303665363063323865623266613762383961336562646135353834356536666633323937333632 +32386638303237646164323837666464623766653537343932643335383461383435303339373364 +36383766316661366130633437616237333264616462366236396238383938663935336537313533 +30333463303263356565316263636566633433336130366366623633313334653462333162653762 +39346665383239376136396461373563616662346337366466656163363634303230396366326137 +34323731326230393237376232333463633439663730626261383330653862663132616163636636 +32333066346231373631626435616566366464613039656466613462653136373030376665663635 +63636335613535666638326130366135333638353033376138396630633364336565613931643130 +30313465353865623537373737336235393730303862386465336132373530373131313263613138 +33396235316265376336313430373064636461316530346166313466373036313337626439336336 +39646533393231626236323339373262636566343930616361616633626339623163313636623064 +31333266666664613337393331306336663331346363643734646432353631326464613266393531 +34666363653730383634643766663234393565383965653263666661336562656131386139346339 +36303663323164393230303835323333396437343334366565343863326566346566643239396164 +39623431393862613361663339363264306634386266376633663134653862643864643133366239 +62666535353866393239636230333266323031363466646662616635353566663433373830633831 +61393738643834376539323837396539323231313039386534333565386334303964633261313038 +65616161616539343732343964376634356236343730303165663237636232633837303634316434 +34336539393939626334396239336532376665386531393239636564323432323164616537333232 +32343132343137343264333235366563303261666130643439323038626238336236653334643164 +30626431383161323638326264326338653136393634333562376162623965336536373761306466 +62666432646137333031353032656330323734383131613730633830316632323262633533396236 +65303563376234346634623939333634653735373462383963336163613338316435396535376638 +33393934356561666266333233393931386137666561336363396265363239336637616661653663 +66306638636534343866653665626163376238323034336538386336333766313439356266326231 +38653863643534393861323636353666313337633063653639313839646661363937386361356164 +38663538633635306431383063353463636435633239663264366339386465663261353731326635 +62633532333931363236633666376563666630656431336166366333383562653036316233336535 +64353938333766393739303637336334626436326533663136643235636534373966333630346231 +37626666333230306137633538616563336633626663383966303139306361383233653738353932 +38353735336466363739373561383133623162376433656565383530616230663638646536386432 +64346264333438643838616666363065356233393839336538656238366637323366663039623533 +34316335616236393661633238633032306366653334396536346438633839323736343264333833 +32636361613764656561633666383730333435613332643235376461306334306335613138373931 +63623862316238383432623230643934656266323232303735333762653865306562653435303634 +38643332666639383633383561633534353335376332343239373338643466303938656339633430 +63346539373562346137616330396162353665353838326463653863366166316535643934356334 +35636538376433346464326133333262663663386137373931623362613737326333346431396561 +32393135646634343534366264626138626661633831366665333361333134356430353666316633 +38623830306134666466343735623763333431343337396165613861396162656531626231633961 +66623161363437613531396339363537353539303439353035633563663536313038366231366633 +34383262366336663361653839376464303336656131663064666666316363616463633439656431 +39643330363630376165343836326365306537306366323332346665353561616538346465666437 +39666337376132643261633566616436353365306662306163353235356630626132636361636661 +39323465376261343530636365613366656636613430353737366263626537306462393764633135 +36636434643565313139353933353261383463376438386264383733646535316635353866613835 +36393137353462323865343032666163383264326134346132353361373834633534353361653333 +66626437323135343633363465393635386661613737633236316330313963303439393833626530 +35643738646465313262343432396266646639303462333131306631373263373761623666613130 +38633362353734313438346565313135623732626639336437376435613538643365303934326439 +30323963323631326333613765363363626465663937386663653234363239326336626664373539 +31323865636534366564393537313531376263626137376433643233376239313433633562366131 +31643538666563646338326336653036366134363834643639356266653862333931373331643136 +32623830633364353064353632303738666533656466306264623165303738663763323464626634 +35656338353232626262323136353733663934333466346337373934313534373664663232643666 +34363731373535393666333530623030343039666532333237613937356430656238613064613431 +37316362326562303631666664633931313763646632323837663465393262633238333364353039 +66336535393133616630353861616334393033643831623532623766363462613461313364313837 +37363561663437626664303939346539626430316466633532366434393833353663303033383137 +38363439653933353738336136323566626363613163626333386366393430383063383464393861 +36386333323565653639323336326337366664643061343264353763666537383638656432303539 +39666433363038626363323634333763323339633831313165373765646537653735306630343938 +33326534366636373534333033643534636462316634383237653639303933316165626630366562 +61653165623336666264356432303137353633383834396561663565633439646461633865373163 +37666237613433326131346365336332386238626264326562383861653733383231656132383239 +38363931666466336631663762333632393933323831623530626130353565643265343732353530 +37346466636537616166616163346366646134393636613838316564333139363733363861303161 +32386330666633313038633762646164643364623034313464613964656633383030636439613530 +30613962326637656239346434623031333662623933366331336663666237376233356633383135 +34653438643131393166633139373966393631373935663234373930336563363530633166343139 +32393331363835326131343162663438633532663739373436383137666239303964643736626239 +64363336666164366163666264333864323639373233316361643965343037633335336566313461 +61373831643134383666303037393637346665326663306165623235383966396236383938303631 +63636336353766346435633632633463356630616538623966323331633966663433633636303435 +38383239373733343638363464633833613532353136376138633863633136363338633033363231 +32383535663530326331346330396138613264303631333137653264363166663730353365346230 +61323062633137656531613236623761313538336463306564396666393162653461356233383434 +64313635356430353430393665643563393131326632326466393064633639393932343865303862 +38653037353033353234343063333330613365313636373130303963326464666161333536666333 +61616636383135636566336434346539613338383461633064313134366564366665306631616565 +61353934333961653738633239666566356463363830333137313835326231636330633065373135 +38306366383565383063626230633366666561623030663163626635353261666564343635303939 +61313538353337353334613666616237346433343630666233316432373337326131363865346531 +34356132663037613965346336353964643230643636393837333131343134633639636238323335 +62383036336364623063666430316337323432653762333230396435373165343564633631376162 +61366438393932626230356363346361313536346162323434396630343564343163336230363839 +66353832663332396163383633333837346365633061636263663534353133643237643533393334 +62393932383563383432306264363762636530366466383833343534356234353165303464383063 +38666133393439653164366565383338373334306436303235373663636662326134363235306631 +36616138323165623237336465633161616139383663643033383335353766313532623238663961 +37323632343733613463386165643965643962643661373530383866393566396531316664653734 +36666565633063646161643265653839333233633666326266303035623466643963626132643366 +35373633653163323232623031363731336339616434386534336335383931306331623332653266 +65323636393835383862656561633237346366616633663362323235316431393336386462313131 +65363664663933323135653864643139663366376131323236306263333462643533663561616461 +32656531383430336663343637356130383764366361376263383035373132663438636332376538 +62393831363161653635653930366363343433666162396431633939656139316237303064636364 +63386661333338663737366261336134626261366137393831383136646438363065663237653535 +37623165626363353938613138346233373231626265323664373939613931306464363839616333 +65393036306134666566623965613265383562353436643034313666366239333663383661383339 +63383264363638373439306135356636613466333137643765613533613934613262396530323930 +34613137626131376439323035316164383931663063656137653363356162396266383034376362 +33326131396162373835346338656164623162316538376332613835343962313264623934626265 +63643962333263323965333438333638353964313965313539333661306531663337326562363464 +33373732336131363434376132316461396635373862326431353935663566336565306630343735 +34613639663231303133623862346338316665323363343536306434343538653363313834343534 +36346566386330356163346463623564643762303839623833656336333862376166346538323764 +34373439343666343937623132383461383232616664633633666664393664316665663166363836 +32383265636263343164396239356163333532353330313330393164643333336338373431636666 +31333731646262633061616361323339343330336665653864313434383132613631666637333661 +35333931323861323535356634353739383936633762643138333533353432373866343861633437 +37663132653261636437643134306461623061383434346363613361643130653066393234363432 +34653561376632383031626439343535363734353763623833336663643630623636623964356631 +34373866313431383563376664646539316363363162353364636366623433666433633837646437 +65306336366637313437383739306138396562613565326235623666646264666461623061313465 +61633261333361396464366434386437356133353933373964363233653036653935326363623034 +32303565633833346265616562333432663061613237353734353361666135633763626133333261 +31363336383637333334343664316266653939663366393961323963383632363432363666343733 +64306631336561383339353836306334313830633565623065323462643830366136333632663064 +64343034656137373335316336353934643561373765656665643864376361663061346462316636 +33323662376430356265376330633132353961363564666362303934383761343131653231653534 +64303065353235393963363663373862626331396334646162633237663562396232336436636632 +63623134303633363261363766376339666666373138343264323036626633616530306163303566 +32636233306234303164613334633739396632396161656635633431383632363832346362366663 +62376239626433613935643737313736623230356366616137653165633634313531613364356666 +35623662666539323135623536396534656364393333623161376539386132313664323838343766 +35376265323535343132363136653138333665353738656431616432343562386661316163323861 +37373665386432343039303231643835306634626437633535316439323633326364663333366661 +64646136396436353065383965396365346466373766343934323362316136333730373139343066 +66633232343466326266363462323936363330383037663266346337646366313264313635393863 +63373164323166346638623931366234346538626639366338356664326333636264393662656131 +30353836313533363164613435353338303665353536643763636139393164313339623533393261 +64363165313866343136323935393236633939316364313238663639303963326232323436666433 +37363262383936326266396365396438393438386166616366323037393530326666343466323131 +63393030643563643064386631656533396337393461363761333235313663636637616230646130 +31336435646262306333326637653234333766653831666664353530386234383632393435393363 +38646432366331303663623736623733313834363234326461323566303731373438663363303536 +39366337356235336130666562363238336331346162653462646633646435666533613864656339 +33363464373462323364336339363334376136646562656561643631656265623138383561613461 +31653563383766343331353937343536636463356361623531663039366166613630653438626462 +33313534623232613762313863316332383661386630633463303363346465646261663166653066 +65363236306261633831336566393733343333626337303535663864373232376339336565343766 +36373034396463313538666532376563626362656634326437666333323735393736353062313461 +35306634366439363561613239303135313630626465353837313761343438323362386234316361 +31306332353137633064376536643338316235393635363438306430383134353639376232383231 +64643136663462393139373530373733626634313430643161643332303062303864343039663433 +61383765386231323039666133666363383137373663316236396634313635346664656332646639 +36343364343961343833623038343237646138323636343836616265303262333231333536643161 +33643930666137613738653332326330366436633063313431646237626639306638373936636664 +64633733366338313261393633656363346365303532656135663837653731666664663439336165 +62626235333865323666383734336539653965313930363639623333663737353839393338623634 +33633561323433393937623162316436623665373863356431653365613662373931613537306465 +39616465646136633761653031326639393365646130346362613462353963636133376436326431 +64616365623438333035336536343162323734366139666462616530393061303932313035613634 +63383436636234396631383161656139346530316139396166323533636333616537386164333230 +63666435333262653835326236373564326162356234303263353839316563366634636136353761 +61326230366134396438653163396539666630376263393561633362636532356636386265333932 +31363434393831373362343235376163663265623235653632626566343431613231633634626432 +39303236643431353533323231623262396638656337363631363562363361346436303366616537 +64343561366632663338643731623265613737663164626336303662636437323132323539353264 +62363934383562633635343338326162363934663836336337306265626364363339393636386438 +62366638393331336132646232313434306238353739336362326262633334643865626433653639 +31643337373235323835316661383761373334343434383431643864366438323931343538326362 +62343831396264363636313165313034623864373565303664636137363363386535373633346133 +62353863623237363335323438313730316233313436366332323563613466316339643161646164 +36666330306561326430643662643262383563663765623464613539646633393464636136353238 +38653239343536373435386139346537373338643563313166326139646333636263306563393337 +35383836663335626262376531373363353637376433363335366237393366633237613165613836 +39626135636265326537666135353138363531353532633530376635306532643663343638373333 +65336332326161303939386161653566333838366335346165633839666434653164366433306464 +66333462373765373162323336643737656532363933383332323238646466373537386465303134 +61613465383138323662393934393963613230653831303864363333646139313138303534373231 +37393639613632346438363235646634633564306632393339346335383365623730393034313038 +33623334633330626663346464336361396239316235393035363031653466613765623634386639 +3063 diff --git a/compose/playbooks/prep_ubuntu/README.md b/compose/playbooks/prep_ubuntu/README.md new file mode 100644 index 0000000..b2e8544 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/README.md @@ -0,0 +1,4 @@ +====================================================================== +Playbook information +====================================================================== +Плейбук по базовой подготовке операционной системы Ubuntu \ No newline at end of file diff --git a/compose/playbooks/prep_ubuntu/ansible.cfg b/compose/playbooks/prep_ubuntu/ansible.cfg new file mode 100644 index 0000000..20d7065 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +ansible_managed="Ansible managed" +host_key_checking=False +inventory=inventory/hosts diff --git a/compose/playbooks/prep_ubuntu/defaults/main.yml b/compose/playbooks/prep_ubuntu/defaults/main.yml new file mode 100644 index 0000000..11163dc --- /dev/null +++ b/compose/playbooks/prep_ubuntu/defaults/main.yml @@ -0,0 +1,9 @@ +--- +# defaults vars +# ansible_python_interpreter: "/usr/libexec/platform-python" +ansible_ssh_pipelining: "true" +ansible_user: "gem-admin" +ansible_ssh_transfer_method: "piped" +ansible_ssh_common_args: "-o StrictHostKeyChecking=no" +ansible_port: 22 + diff --git a/compose/playbooks/prep_ubuntu/handlers/main.yml b/compose/playbooks/prep_ubuntu/handlers/main.yml new file mode 100644 index 0000000..c09dec7 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/handlers/main.yml @@ -0,0 +1,5 @@ +--- +# handlers file + + + diff --git a/compose/playbooks/prep_ubuntu/inventory/hosts b/compose/playbooks/prep_ubuntu/inventory/hosts new file mode 100644 index 0000000..7dffa3e --- /dev/null +++ b/compose/playbooks/prep_ubuntu/inventory/hosts @@ -0,0 +1,6 @@ + +[prep-host] +cw-sya-ldap-001 ansible_host=10.130.0.16 +cw-sya-store-001 ansible_host=10.130.0.12 +cw-sya-iam-001 ansible_host=10.130.0.41 +cw-sya-reg-001 ansible_host=10.130.0.42 diff --git a/compose/playbooks/prep_ubuntu/main.yml b/compose/playbooks/prep_ubuntu/main.yml new file mode 100644 index 0000000..6c5502a --- /dev/null +++ b/compose/playbooks/prep_ubuntu/main.yml @@ -0,0 +1,22 @@ +--- +# Плей по базовой подготовке сервера Linux (Ubuntu) +- name: Base prepate Linux server +# hosts: gt-demo-ldap + hosts: all + + gather_facts: true + become: true + vars_files: + - vars/base_conf.yml + - vars/secret.yml + - defaults/main.yml + pre_tasks: + - import_tasks: tasks/check_os_version.yml + roles: + - role: ubuntu_base_conf + when: ansible_distribution == "Ubuntu" + - role: ubuntu_install_docker + when: ansible_distribution == "Ubuntu" and docker_install == "yes" + post_tasks: + - import_tasks: tasks/reboot.yml + when: reboot == "yes" diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/README.md b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/README.md new file mode 100644 index 0000000..e9cd313 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/README.md @@ -0,0 +1,4 @@ +====================================================================== +Role information +====================================================================== +Роль для базовой настройки Ubuntu (Gemspace) \ No newline at end of file diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/handlers/main.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/handlers/main.yml new file mode 100644 index 0000000..c09dec7 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/handlers/main.yml @@ -0,0 +1,5 @@ +--- +# handlers file + + + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/add_admin_user.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/add_admin_user.yml new file mode 100644 index 0000000..3e336f9 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/add_admin_user.yml @@ -0,0 +1,46 @@ +--- +# Добавление локального администратора +- name: Create local admin + block: + - name: Add local admin + user: + comment: "{{ item.comment }}" + createhome: true + name: "{{ item.name }}" + shell: /bin/bash + password_lock: true + force: true + loop: + - { name: 'gem-admin', comment: 'Gem local administrator' } + + - name: Add SSH keys + authorized_key: + user: "{{ item.user }}" + key: "{{ item.ssh_keys | join('\n') }}" # Combine keys into a single string + exclusive: "{{ item.exclusive }}" + no_log: true + loop: + - user: gem-admin + ssh_keys: + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCGF42ADoauvpQeNW9I3dBvra4+/aK3zz0y8moBKngdwLbg/yu5dYlB7p4w2qp3QEFcHatyBHrjezKOEO5qM7HFx2Yp0dsR7j25ZhLc8Oy85eFJIKRu4DTJLahNgp+ybL+zjadRVGuc6xQtFemOtFTNzeMhwxvgLF312/pWnVlN3KIoIbOxOwnp0hr1yvKivDRTmDUI3bNvgCLSnap5fxcBZZklz+AzshIH9rY0W86VCewACRnPRcaE94O+4XjibqYi8vQPGUAu9NpRAPvuDbp1N5BgwhLcDx/XdQDcyhMdtLbHJ/I1WhaTLJjUDXVp3wcC4E7jpzXLBqkwPneplpVHT2Qk5AGp0R8Vb+q4TMLRbgm00036CcXY1Y/6VtAd1c3+QlXMSVMDEHBMBJ/NBM8cKkPhhBT8C1Tt660IFRErx8C48IqpGfHjHQZn8Xf0RWIyZ28c/x6mOhHJqqFAsPCsGsYcWVdAZBD53tWHGdjYcLGeI3UCYBFnnj4fEvQUUnBE3JB1NdkeVxYElbh7SktVTh3G3kNFAwWYgwn31Qh74jWpN11H8m5XM0I3R2TGzi7yuS8zKOKaEZwObSNVTfBbPHh6uVK3olIsiznAsI19jqrg+QQjStaNhHDcN/SZTxboy7q7Rnigl2cJOHM2rxm8NmuMuTHdPKlpbigvq7PFMQ== gem-admin" + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC99En90Q7+VECxJLvVJY4TjasnFxC77YHpEebNeJg8iWapjvFxQ5ROOQX43x0kRKIZrnj3aQmpSvs+RuvWAxszm3BE4jiSftL49ImSMdmyoiGV5l1WcV1HJrmwz7jq5Eq8P/iMw3hVkhWU6b860kWpAhFiaW/g58BHJHVYn4M+pLDWk2NRkvHD4Ez1rtH28hXqrrm+TD/KhxLUrqQdytvYi5trzWQbahtpOtev0Dyi8oBdj6Jph/pB3mzZnWFGP2r106x4bKlvzKlLgNn9yPgygknDIEmD9dIEf2sJ/WbxqurR0x+Id3rpAiyvZWnY0O4CNcP9DIOrM0onz2he+hJTH+Kr8tiJBfpqoboSnyIdPfh2dMGGpGxPYoghVBg6ylkQ6ZUB8xUTTjfzCxxNF7TgMI064iXi+RWwepknLxw2vcgiSRi/nnv9NFJta+QOskK+05YXecWcnJVvREmYkGSzKEkuzwxEWwYIc2/JAngQxeenGaBAl9mDKdFPyZcQUy0= leonisa@Leonids-MacBook-Pro.local" + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC9dzp4d6A9ZfVOXmHdiSW05qZbCGWBm8W0+KTlqEaRssliHHmrWSntiSvoeG2nQPJKBA5MAi476T/hmT2ym1oZxvRdyBODRw/UdXboHTXejXivtfhVT0ghcKOrllDbwzM/J9PT4k7rdefduIpv0wGHXzIVFqU1ZdjqDVqixuPq8dVSJJIOI5am6AJ6Of+U87FNC91GlGEezq8+Xo55BvUTKPjxnoHWUKVvvT6ci78i8I7Ux1Dx48lj90J61z9BIxvDZbWDDUY9gL2E0TSsYYDws5uX/+OSi3BIzJvMdzcn5LUTjIKX5FLYhdpagwqX2vaziI3S51RSpsqC6w76awKmcNbKfZzn8bXsvbK6pnwGKhFYBYZKui2piqq8rZ5MEHabHmEf1EdCtVW5Q0FNZzBKRFy6Sa5FwdzJPCmdoVOCtwXVZtKgUGHksxtWpMuuvO5QcXDoOqyCtTnk79S1fOYfQWbtTeKOpHiIONCgl6/CzZdoB8FXYRuyLtXmRTQy7rM= antropov.a.b-2023-09-25" + exclusive: true + - user: leonid.sokurov + ssh_keys: + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC99En90Q7+VECxJLvVJY4TjasnFxC77YHpEebNeJg8iWapjvFxQ5ROOQX43x0kRKIZrnj3aQmpSvs+RuvWAxszm3BE4jiSftL49ImSMdmyoiGV5l1WcV1HJrmwz7jq5Eq8P/iMw3hVkhWU6b860kWpAhFiaW/g58BHJHVYn4M+pLDWk2NRkvHD4Ez1rtH28hXqrrm+TD/KhxLUrqQdytvYi5trzWQbahtpOtev0Dyi8oBdj6Jph/pB3mzZnWFGP2r106x4bKlvzKlLgNn9yPgygknDIEmD9dIEf2sJ/WbxqurR0x+Id3rpAiyvZWnY0O4CNcP9DIOrM0onz2he+hJTH+Kr8tiJBfpqoboSnyIdPfh2dMGGpGxPYoghVBg6ylkQ6ZUB8xUTTjfzCxxNF7TgMI064iXi+RWwepknLxw2vcgiSRi/nnv9NFJta+QOskK+05YXecWcnJVvREmYkGSzKEkuzwxEWwYIc2/JAngQxeenGaBAl9mDKdFPyZcQUy0= leonisa@Leonids-MacBook-Pro.local" + exclusive: true + - user: a.antropov + ssh_keys: + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC9dzp4d6A9ZfVOXmHdiSW05qZbCGWBm8W0+KTlqEaRssliHHmrWSntiSvoeG2nQPJKBA5MAi476T/hmT2ym1oZxvRdyBODRw/UdXboHTXejXivtfhVT0ghcKOrllDbwzM/J9PT4k7rdefduIpv0wGHXzIVFqU1ZdjqDVqixuPq8dVSJJIOI5am6AJ6Of+U87FNC91GlGEezq8+Xo55BvUTKPjxnoHWUKVvvT6ci78i8I7Ux1Dx48lj90J61z9BIxvDZbWDDUY9gL2E0TSsYYDws5uX/+OSi3BIzJvMdzcn5LUTjIKX5FLYhdpagwqX2vaziI3S51RSpsqC6w76awKmcNbKfZzn8bXsvbK6pnwGKhFYBYZKui2piqq8rZ5MEHabHmEf1EdCtVW5Q0FNZzBKRFy6Sa5FwdzJPCmdoVOCtwXVZtKgUGHksxtWpMuuvO5QcXDoOqyCtTnk79S1fOYfQWbtTeKOpHiIONCgl6/CzZdoB8FXYRuyLtXmRTQy7rM= antropov.a.b-2023-09-25" + exclusive: true + + - name: Sudo permissions + community.general.sudoers: + name: "{{ item }}-access" + user: "{{ item }}" + commands: ALL + nopassword: true + state: present + loop: + - "gem-admin" \ No newline at end of file diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/apt_config.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/apt_config.yml new file mode 100644 index 0000000..1f221ae --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/apt_config.yml @@ -0,0 +1,9 @@ +--- +# Настройка apt +- name: Set apt config no check-valid-until + template: + src: "etc/apt/apt.conf.d/10-no-check-valid-until.j2" + dest: "/etc/apt/apt.conf.d/10-no-check-valid-until.conf" + + + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/cert_ca_import.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/cert_ca_import.yml new file mode 100644 index 0000000..3288519 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/cert_ca_import.yml @@ -0,0 +1,14 @@ +--- +# Установка корневых сертифифкатов УЦ +- name: Install CA certs + block: + - name: Import CA certs + copy: + content: "{{ rootca_public_key }}" + dest: "/usr/local/share/ca-certificates/rootca_local.crt" + register: cert_updated + + - name: Update CA certs + shell: | + update-ca-certificates + when: cert_updated['changed'] diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/dnsmasq_config.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/dnsmasq_config.yml new file mode 100644 index 0000000..a771715 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/dnsmasq_config.yml @@ -0,0 +1,75 @@ +--- +# Конфигурирование сервиса локального кэширования dns запросов dnsmasq +- name: Gather the package facts + package_facts: + manager: auto + +- name: Configure dnsmasq + block: + - name: Stop and disable systemd-resolved service + service: + name: systemd-resolved + state: stopped + enabled: false + + - name: Copy dnsmasq config + template: + src: "etc/dnsmasq.d/local-cache.j2" + dest: "/etc/dnsmasq.d/local-cache.conf" + owner: root + group: root + mode: '0755' + register: dns_updated + + - name: Copy dhcpclient config + template: + src: "etc/dhcp/dhclient.conf.j2" + dest: "/etc/dhcp/dhclient.conf" + owner: root + group: root + mode: '0644' + register: dhcp_updated + + - name: Started Dnsmasq + service: + name: dnsmasq + state: started + enabled: yes + + - name: Pause for 5 seconds to start Dnsmasq + ansible.builtin.pause: + seconds: 5 + + - name: Remove /etc/resolv.conf + shell: | + rm -f /etc/resolv.conf + + - name: Add base /etc/resolv.conf + copy: + dest: /etc/resolv.conf + content: | + nameserver 127.0.0.1 + + - name: Restarted Dnsmasq + service: + name: dnsmasq + state: restarted + loop: + - dnsmasq + when: dns_updated['changed'] + + # - name: Restarted Networking + # service: + # # name: networking + # name: systemd-networkd + # state: restarted + # when: dhcp_updated['changed'] + + - name: Rebooting system... + ansible.builtin.reboot: + reboot_timeout: 180 + when: dhcp_updated['changed'] and reboot == "yes" + when: + - '"dnsmasq" in ansible_facts.packages' + + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/enable_services.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/enable_services.yml new file mode 100644 index 0000000..38db340 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/enable_services.yml @@ -0,0 +1,16 @@ +- name: "Enable various systemd-services" + systemd: + enabled: yes + name: "{{ item }}" + with_items: + - rsyslog + - cron.service + +- name: "Start various systemd-services" + systemd: + enabled: yes + name: "{{ item }}" + state: started + with_items: + - rsyslog + - cron.service diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/fstrim-timer_enable.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/fstrim-timer_enable.yml new file mode 100644 index 0000000..ce18ece --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/fstrim-timer_enable.yml @@ -0,0 +1,8 @@ +--- +# Включение сервиса fstrim timer +- name: Enable fstrim.timer + ansible.builtin.systemd: + name: fstrim.timer + state: started + enabled: yes + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/history_config.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/history_config.yml new file mode 100644 index 0000000..a153a79 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/history_config.yml @@ -0,0 +1,4 @@ +- name: Add date to history + lineinfile: + dest: /root/.bashrc + line: 'export HISTTIMEFORMAT="%F %T "' \ No newline at end of file diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/hosts_file_config.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/hosts_file_config.yml new file mode 100644 index 0000000..760a291 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/hosts_file_config.yml @@ -0,0 +1,14 @@ +--- +# Базовый конфиг файла /etc/hosts +- name: Add base /etc/hosts config + copy: + dest: /etc/hosts + content: | + 127.0.0.1 localhost + {{ ansible_default_ipv4.address }} {{ ansible_hostname }}.{{ local_domain }} {{ ansible_hostname }} + + + + + + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/install-pkg.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/install-pkg.yml new file mode 100644 index 0000000..6fac107 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/install-pkg.yml @@ -0,0 +1,34 @@ +--- +# Установка дополнительных пакетов +- name: Update repo cache + command: apt update + +- name: Install additional packages + apt: + name: '{{ item }}' + state: present + update_cache: yes + loop: + - dstat + - sysstat + - tcpdump + - dnsutils + - vim + - wget + - curl + - chrony + - python3 + - python3-pip + - perl + - lsof + - net-tools + - traceroute + - python3-lxml + - rsyslog + - logrotate + - htop + - packagekit + # - python3-full + - dnsmasq + - unzip + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/journald_config.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/journald_config.yml new file mode 100644 index 0000000..0aa840b --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/journald_config.yml @@ -0,0 +1,18 @@ +--- +# Настройка конфигурации journald +- name: Configure journald + block: + - name: Add journald config + template: + src: "etc/systemd/journald.j2" + dest: "/etc/systemd/journald.conf" + register: journald_updated + + - name: Restart systemd-journald + systemd: + name: systemd-journald + state: restarted + when: journald_updated['changed'] + + + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/logrotate_config.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/logrotate_config.yml new file mode 100644 index 0000000..fe76d36 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/logrotate_config.yml @@ -0,0 +1,9 @@ +--- +# Настройка ротации логов logrotate +- name: Set logrotate config + template: + src: "etc/logrotate.j2" + dest: "/etc/logrotate.conf" + + + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/main.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/main.yml new file mode 100644 index 0000000..e24f9bc --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/main.yml @@ -0,0 +1,79 @@ +--- +# Базовый конфиг файла /etc/hosts +- name: Add base /etc/hosts config + import_tasks: hosts_file_config.yml + +# Установка временной зоны +- name: Set timezone + import_tasks: timezone_config.yml + +# Настройка конфигурации ssh +- name: Configure ssh + import_tasks: ssh_conf.yml + +# # Добавление локального администратора +# - name: Create local admin +# import_tasks: add_admin_user.yml + +# Установка дополнительных пакетов +- name: Install additional packages + import_tasks: install-pkg.yml + +# Настройка синхронизации времени +- name: Time sync configure + import_tasks: time_sync_config.yml + +# Настройка dnsmasq +- name: Configure dnsmasq + import_tasks: dnsmasq_config.yml + +# Настройка swap +- name: Configure swap + import_tasks: swap_config.yml + +# Настройка конфигурации параметров ядра +- name: Configure kernel parameters + import_tasks: sysctl_config.yml + +# Включение сервиса fstrim timer +- name: Enable fstrim.timer service + import_tasks: fstrim-timer_enable.yml + +# Настройка apt +- name: Configure apt + import_tasks: apt_config.yml + +# Установка корневых сертифифкатов УЦ +- name: Install CA certs + import_tasks: cert_ca_import.yml + +# Настройка конфигурации journald +- name: Configure joutnald + import_tasks: journald_config.yml + +# Настройка конфигурации logrotate +- name: Configure logrotate + import_tasks: logrotate_config.yml + +# Настройка history +- name: History configure + import_tasks: history_config.yml + +# Включение сервисов +- name: Enable services + import_tasks: enable_services.yml + +# Установка пароля для root +- name: Set root password + import_tasks: set_root_pass.yml + +# Настройка ufw +- name: Configure ufw + import_tasks: ufw_conf.yml + when: configure_firewall == "yes" + +# Обновление пакетов +- name: Update packages + # ignore_errors: true + import_tasks: update_packages.yml + when: update_pkg == "yes" diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/profile_config.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/profile_config.yml new file mode 100644 index 0000000..99c861b --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/profile_config.yml @@ -0,0 +1,19 @@ +--- +# Настройка профиля пользователя +- name: Configure user profile + block: + - name: Change login.def + lineinfile: + path: "{{ item.path }}" + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + state: present + loop: + - { path: '/etc/login.defs', regexp: '^UID_MAX', line: 'UID_MAX 999999999' } + - { path: '/etc/login.defs', regexp: '^GID_MAX', line: 'GID_MAX 999999999' } + + + + + + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/set_root_pass.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/set_root_pass.yml new file mode 100644 index 0000000..2521630 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/set_root_pass.yml @@ -0,0 +1,7 @@ +--- +# Установка пароля для root +- name: Change password for root + ansible.builtin.user: + name: root + state: present + password: "{{ root_pass | password_hash('sha512') }}" \ No newline at end of file diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/ssh_conf.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/ssh_conf.yml new file mode 100644 index 0000000..564ce5f --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/ssh_conf.yml @@ -0,0 +1,22 @@ +--- +# Настройка конфигурации ssh +- name: Configure ssh + block: + - name: Copy sshd_config (server config) + template: + src: "etc/ssh/sshd_config.j2" + dest: "/etc/ssh/sshd_config" + owner: root + group: root + mode: '0600' + register: sshd_updated + + - name: Restart sshd service + service: + name: ssh + state: restarted + when: sshd_updated['changed'] + + + + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/swap_config.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/swap_config.yml new file mode 100644 index 0000000..6aa9fe2 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/swap_config.yml @@ -0,0 +1,26 @@ +--- +# Настройка swap +- name: Check whether "/swapfile" exists + stat: + path: /swapfile + register: swap_check + +- name: Configure dnsmasq + block: + - name: Allocate the swap file + shell: fallocate -l {{ swap_size }} /swapfile + + - name: Change permission of the swap file + file: + path: /swapfile + mode: 600 + + - name: Create a swap area on the swap file + shell: mkswap /swapfile + + - name: Activate the swap file as a swap memory + shell: swapon /swapfile + + - name: Append configuration in /etc/fstab + shell: echo "\n/swapfile swap swap defaults 0 0\n" >> /etc/fstab + when: swap_check.stat.exists != true \ No newline at end of file diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/sysctl_config.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/sysctl_config.yml new file mode 100644 index 0000000..52326b0 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/sysctl_config.yml @@ -0,0 +1,19 @@ +--- +# Настройка конфигурации параметров ядра +- name: Add sysctl parameters + ansible.posix.sysctl: + name: "{{ item.param }}" + value: "{{ item.value }}" + sysctl_set: true + reload: true + loop: + - { param: 'vm.swappiness', value: '10' } + - { param: 'net.ipv6.conf.all.disable_ipv6', value: '1' } + - { param: 'net.ipv6.conf.default.disable_ipv6', value: '1' } + - { param: 'net.ipv6.conf.lo.disable_ipv6', value: '1' } + + + + + + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/time_sync_config.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/time_sync_config.yml new file mode 100644 index 0000000..167e282 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/time_sync_config.yml @@ -0,0 +1,24 @@ +--- +# Настройка синхронизации времени +- name: Configure NTP + block: + - name: Install additional packages + apt: + name: chrony + state: present + update_cache: yes + + - name: Set chrony config + template: + src: "etc/chrony.j2" + dest: "/etc/chrony/chrony.conf" + register: ntp_updated + + - name: Enable and restart chronyd service + service: + name: chronyd + state: restarted + enabled: yes + when: ntp_updated['changed'] + + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/timezone_config.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/timezone_config.yml new file mode 100644 index 0000000..f6f3654 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/timezone_config.yml @@ -0,0 +1,11 @@ +--- +# Установка временной зоны +- name: Set timezone to Europe/Moscow + become: true + community.general.timezone: + name: Europe/Moscow + + + + + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/ufw_conf.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/ufw_conf.yml new file mode 100644 index 0000000..b4ada10 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/ufw_conf.yml @@ -0,0 +1,49 @@ +--- +# Настройка ufw +- name: Configure ufw + block: + - name: Gather the package facts + package_facts: + manager: auto + + - name: Install additional packages + apt: + name: '{{ item }}' + state: present + update_cache: yes + loop: + - ufw + when: + - '"dnsmasq" in ansible_facts.packages' + + - name: Enable ufw service + systemd: + name: ufw.service + state: started + enabled: yes + + - name: Default allow outgoing traffic + community.general.ufw: + default: allow + direction: outgoing + + - name: Default deny incoming traffic + community.general.ufw: + default: deny + direction: incoming + + - name: Allow ssh traffic + community.general.ufw: + rule: allow + port: 22 + proto: tcp + + - name: Enable UFW + community.general.ufw: + state: enabled + policy: deny + + + + + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/update_packages.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/update_packages.yml new file mode 100644 index 0000000..154e232 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/tasks/update_packages.yml @@ -0,0 +1,20 @@ +--- +# Обновление DEB пакетов + +- name: Update DEB Packeges + block: + + - name: Update repo cache + apt: + update_cache: yes + + - name: Upgrade OS + apt: + upgrade: dist + autoclean: yes + register: update_state + + - name: Clean old packages + apt: + autoclean: yes + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/apt/apt.conf.d/10-no-check-valid-until.j2 b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/apt/apt.conf.d/10-no-check-valid-until.j2 new file mode 100644 index 0000000..35996b0 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/apt/apt.conf.d/10-no-check-valid-until.j2 @@ -0,0 +1 @@ +Acquire::Check-Valid-Until false; \ No newline at end of file diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/chrony.j2 b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/chrony.j2 new file mode 100644 index 0000000..89b8382 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/chrony.j2 @@ -0,0 +1,39 @@ +# Use public servers from the pool.ntp.org project. +# Please consider joining the pool (http://www.pool.ntp.org/join.html). +server ntp.msk-ix.ru iburst +server 0.ru.pool.ntp.org +server 1.ru.pool.ntp.org +server 2.ru.pool.ntp.org + +# Record the rate at which the system clock gains/losses time. +driftfile /var/lib/chrony/drift + +# Allow the system clock to be stepped in the first three updates +# if its offset is larger than 1 second. +makestep 1.0 3 + +# Enable kernel synchronization of the real-time clock (RTC). +rtcsync + +# Enable hardware timestamping on all interfaces that support it. +#hwtimestamp * + +# Increase the minimum number of selectable sources required to adjust +# the system clock. +#minsources 2 + +# Allow NTP client access from local network. +#allow 192.168.0.0/16 + +# Serve time even if not synchronized to a time source. +#local stratum 10 + +# Specify file containing keys for NTP authentication. +#keyfile /etc/chrony.keys + +# Specify directory for log files. +logdir /var/log/chrony + +# Select which information is logged. +#log measurements statistics tracking + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/dhcp/dhclient.conf.j2 b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/dhcp/dhclient.conf.j2 new file mode 100644 index 0000000..28ab41d --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/dhcp/dhclient.conf.j2 @@ -0,0 +1,58 @@ +# Configuration file for /sbin/dhclient. +# +# This is a sample configuration file for dhclient. See dhclient.conf's +# man page for more information about the syntax of this file +# and a more comprehensive list of the parameters understood by +# dhclient. +# +# Normally, if the DHCP server provides reasonable information and does +# not leave anything out (like the domain name, for example), then +# few changes must be made to this file, if any. +# + +option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; + +send host-name = gethostname(); +request subnet-mask, broadcast-address, time-offset, routers, + domain-name, domain-name-servers, domain-search, host-name, + dhcp6.name-servers, dhcp6.domain-search, dhcp6.fqdn, dhcp6.sntp-servers, + netbios-name-servers, netbios-scope, interface-mtu, + rfc3442-classless-static-routes, ntp-servers; + +supersede domain-name "{{ local_domain }}"; +supersede domain-name-servers 127.0.0.1; +supersede domain-search "{{ local_domain }}"; +#send dhcp-client-identifier 1:0:a0:24:ab:fb:9c; +#send dhcp-lease-time 3600; +#supersede domain-name "fugue.com home.vix.com"; +#prepend domain-name-servers 127.0.0.1; +#require subnet-mask, domain-name-servers; +# "timeout" Value set by dhcp-all-interfaces +timeout 30; +#retry 60; +#reboot 10; +#select-timeout 5; +#initial-interval 2; +#script "/sbin/dhclient-script"; +#media "-link0 -link1 -link2", "link0 link1"; +#reject 192.33.137.209; + +#alias { +# interface "eth0"; +# fixed-address 192.5.5.213; +# option subnet-mask 255.255.255.255; +#} + +#lease { +# interface "eth0"; +# fixed-address 192.33.137.200; +# medium "link0 link1"; +# option host-name "andare.swiftmedia.com"; +# option subnet-mask 255.255.255.0; +# option broadcast-address 192.33.137.255; +# option routers 192.33.137.250; +# option domain-name-servers 127.0.0.1; +# renew 2 2000/1/12 00:00:01; +# rebind 2 2000/1/12 00:00:01; +# expire 2 2000/1/12 00:00:01; +#} \ No newline at end of file diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/dnsmasq.d/local-cache.j2 b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/dnsmasq.d/local-cache.j2 new file mode 100644 index 0000000..0399bd6 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/dnsmasq.d/local-cache.j2 @@ -0,0 +1,8 @@ +bind-interfaces +listen-address=127.0.0.1 +cache-size=1000 +no-poll +clear-on-reload +no-resolv +server=/{{ local_domain }}/{{ dns_local_server }} +server={{ dns_cloud_server }} \ No newline at end of file diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/logrotate.j2 b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/logrotate.j2 new file mode 100644 index 0000000..1a76b00 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/logrotate.j2 @@ -0,0 +1,21 @@ +# see "man logrotate" for details +# rotate log files daily +daily + +# keep 14 days worth of backlogs +rotate 14 + +# create new (empty) log files after rotating old ones +create + +# use date as a suffix of the rotated file +dateext + +# uncomment this if you want your log files compressed +compress + +# RPM packages drop log rotation information into this directory +include /etc/logrotate.d + +# system-specific logs may be also be configured here. + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/ssh/sshd_config.j2 b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/ssh/sshd_config.j2 new file mode 100644 index 0000000..06ced21 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/ssh/sshd_config.j2 @@ -0,0 +1,140 @@ +# SBT ssh config for SBEL + +# This sshd was compiled with PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin + +# The strategy used for options in the default sshd_config shipped with +# OpenSSH is to specify options with their default value where +# possible, but leave them commented. Uncommented options override the +# default value. + +# If you want to change the port on a SELinux system, you have to tell +# SELinux about this change. +# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER +# +Protocol 2 +Port 22 +#AddressFamily any +#ListenAddress 0.0.0.0 +#ListenAddress :: + +HostKey /etc/ssh/ssh_host_rsa_key +HostKey /etc/ssh/ssh_host_ecdsa_key +HostKey /etc/ssh/ssh_host_ed25519_key + +# Ciphers and keying +#RekeyLimit default none +Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,chacha20-poly1305@openssh.com +KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256 +MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com + +# Logging +#SyslogFacility AUTH +SyslogFacility AUTHPRIV +#LogLevel INFO + +# Authentication: + +LoginGraceTime 3m +PermitRootLogin no +#StrictModes yes +MaxAuthTries 6 +#MaxSessions 10 + +PubkeyAuthentication yes + +# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 +# but this is overridden so installations will only check .ssh/authorized_keys +AuthorizedKeysFile .ssh/authorized_keys + +#AuthorizedPrincipalsFile none + +#AuthorizedKeysCommand none +#AuthorizedKeysCommandUser nobody + +# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts +HostbasedAuthentication no +# Change to yes if you don't trust ~/.ssh/known_hosts for +# HostbasedAuthentication +#IgnoreUserKnownHosts no +# Don't read the user's ~/.rhosts and ~/.shosts files +IgnoreRhosts yes + +# To disable tunneled clear text passwords, change to no here! +#PasswordAuthentication yes +PermitEmptyPasswords no +PasswordAuthentication no + +# Change to no to disable s/key passwords +#ChallengeResponseAuthentication yes +ChallengeResponseAuthentication no + +# Kerberos options +#KerberosAuthentication no +#KerberosOrLocalPasswd yes +#KerberosTicketCleanup yes +#KerberosGetAFSToken no +#KerberosUseKuserok yes + +# GSSAPI options +GSSAPIAuthentication yes +GSSAPICleanupCredentials no +#GSSAPIStrictAcceptorCheck yes +#GSSAPIKeyExchange no +#GSSAPIEnablek5users no + +# Set this to 'yes' to enable PAM authentication, account processing, +# and session processing. If this is enabled, PAM authentication will +# be allowed through the ChallengeResponseAuthentication and +# PasswordAuthentication. Depending on your PAM configuration, +# PAM authentication via ChallengeResponseAuthentication may bypass +# the setting of "PermitRootLogin without-password". +# If you just want the PAM account and session checks to run without +# PAM authentication, then enable this but set PasswordAuthentication +# and ChallengeResponseAuthentication to 'no'. +# WARNING: 'UsePAM no' is not supported in RHEL and may cause several +# problems. +UsePAM yes + +#AllowAgentForwarding yes +AllowTcpForwarding no +#GatewayPorts no +X11Forwarding yes +#X11DisplayOffset 10 +#X11UseLocalhost yes +#PermitTTY yes + +# It is recommended to use pam_motd in /etc/pam.d/sshd instead of PrintMotd, +# as it is more configurable and versatile than the built-in version. +PrintMotd no + +#PrintLastLog yes +#TCPKeepAlive yes +PermitUserEnvironment no +#Compression delayed +ClientAliveInterval 300 +ClientAliveCountMax 3 +#UseDNS no +#PidFile /var/run/sshd.pid +#MaxStartups 10:30:100 +#PermitTunnel no +#ChrootDirectory none +#VersionAddendum none + +# no default banner path +#Banner none + +# Accept locale-related environment variables +AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES +AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT +AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE +AcceptEnv XMODIFIERS + +# override default of no subsystems +Subsystem sftp /usr/libexec/openssh/sftp-server + +# Example of overriding settings on a per-user basis +#Match User anoncvs +# X11Forwarding no +# AllowTcpForwarding no +# PermitTTY no +# ForceCommand cvs server diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/systemd/journald.j2 b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/systemd/journald.j2 new file mode 100644 index 0000000..34ce79a --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_base_conf/templates/etc/systemd/journald.j2 @@ -0,0 +1,29 @@ +[Journal] +Storage=persistent +Compress=yes +#Seal=yes +#SplitMode=uid +#SyncIntervalSec=5m +#RateLimitIntervalSec=30s +#RateLimitBurst=10000 +SystemMaxUse=2G +#SystemKeepFree= +#SystemMaxFileSize= +#SystemMaxFiles=100 +#RuntimeMaxUse= +#RuntimeKeepFree= +#RuntimeMaxFileSize= +#RuntimeMaxFiles=100 +#MaxRetentionSec= +#MaxFileSec=1month +#ForwardToSyslog=no +#ForwardToKMsg=no +#ForwardToConsole=no +#ForwardToWall=yes +#TTYPath=/dev/console +#MaxLevelStore=debug +#MaxLevelSyslog=debug +#MaxLevelKMsg=notice +#MaxLevelConsole=info +#MaxLevelWall=emerg +#LineMax=48K diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/README.md b/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/README.md new file mode 100644 index 0000000..ae41738 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/README.md @@ -0,0 +1,4 @@ +====================================================================== +Role information +====================================================================== +Установка Docker-ce и Docker-compose \ No newline at end of file diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/handlers/main.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/handlers/main.yml new file mode 100644 index 0000000..7479ceb --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/handlers/main.yml @@ -0,0 +1,4 @@ +--- +# handlers file + + diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/tasks/configure_docker.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/tasks/configure_docker.yml new file mode 100644 index 0000000..0aeb46c --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/tasks/configure_docker.yml @@ -0,0 +1,29 @@ +--- +# Настройка Docker +- name: Configure Docker + block: + - name: Make docker config + template: + src: daemon.json.j2 + dest: /etc/docker/daemon.json + mode: 0644 + register: docker_updated + + - name: Enable and start Docker service + service: + name: docker + state: started + enabled: yes + + - name: Restart Docker service + service: + name: docker + state: restarted + when: docker_updated['changed'] + + - name: Add users to a docker group + ansible.builtin.user: + name: "{{ item }}" + groups: docker + loop: "{{ docker_users_list }}" + # when: docker_users_list is defined \ No newline at end of file diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/tasks/install_docker.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/tasks/install_docker.yml new file mode 100644 index 0000000..6cfefa7 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/tasks/install_docker.yml @@ -0,0 +1,35 @@ +--- +# Установка Docker +- name: "Check packages is installed" + package_facts: + manager: "auto" + +- name: "Install Docker" + block: + - name: "Add GPG key" + shell: | + install -m 0755 -d /etc/apt/keyrings + curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc + chmod a+r /etc/apt/keyrings/docker.asc + + - name: "Add the repository to Apt sources" + shell: | + echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ + $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ + sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + apt-get update + + - name: Install docker packages + apt: + name: '{{ item }}' + state: present + update_cache: yes + loop: + - docker-ce + - docker-ce-cli + - containerd.io + - docker-buildx-plugin + - docker-compose-plugin + - docker-compose + when: "'docker-ce' not in ansible_facts.packages" \ No newline at end of file diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/tasks/main.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/tasks/main.yml new file mode 100644 index 0000000..08fc61c --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/tasks/main.yml @@ -0,0 +1,9 @@ +--- + +# Установка Docker +- name: Install Docker + include_tasks: install_docker.yml + +# Настройка Docker +- name: Configure Docker + include_tasks: configure_docker.yml diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/templates/daemon.json.j2 b/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/templates/daemon.json.j2 new file mode 100644 index 0000000..c8a6d5e --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/templates/daemon.json.j2 @@ -0,0 +1,7 @@ +{ + "log-driver": "json-file", + "log-opts": { + "max-size": "{{ docker_log_size }}", + "max-file": "{{ docker_log_files }}" + } +} \ No newline at end of file diff --git a/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/vars/main.yml b/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/vars/main.yml new file mode 100644 index 0000000..8831049 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/roles/ubuntu_install_docker/vars/main.yml @@ -0,0 +1,7 @@ +--- +# vars file +docker_log_size: "100m" # Размер файла логов для Docker (в мегабайтах) +docker_log_files: "3" # Количество файлов логов для Docker +docker_users_list: # Пользователи которых необходлимо добавить в группу docker + - root + - gem-admin diff --git a/compose/playbooks/prep_ubuntu/tasks/check_os_version.yml b/compose/playbooks/prep_ubuntu/tasks/check_os_version.yml new file mode 100644 index 0000000..2909c8b --- /dev/null +++ b/compose/playbooks/prep_ubuntu/tasks/check_os_version.yml @@ -0,0 +1,15 @@ +--- +# Проверка версии ОС +- name: Check OS version + block: + # - name: DEBUG OS version + # debug: + # msg: + # - "OS: {{ ansible_distribution }}" + # - "Version: {{ ansible_distribution_version }}" + # - "Major version: {{ ansible_distribution_major_version }}" + + - name: OS version not supported + fail: + msg: "Operating system {{ ansible_distribution }} ver. {{ ansible_distribution_major_version }} not supported" + when: ansible_distribution not in ['Ubuntu'] \ No newline at end of file diff --git a/compose/playbooks/prep_ubuntu/tasks/reboot.yml b/compose/playbooks/prep_ubuntu/tasks/reboot.yml new file mode 100644 index 0000000..8700aef --- /dev/null +++ b/compose/playbooks/prep_ubuntu/tasks/reboot.yml @@ -0,0 +1,9 @@ +--- +# Перезагрузка системы +- name: Rebooting system... + ansible.builtin.reboot: + reboot_timeout: 360 + + + + diff --git a/compose/playbooks/prep_ubuntu/vars/base_conf.yml b/compose/playbooks/prep_ubuntu/vars/base_conf.yml new file mode 100644 index 0000000..edbae76 --- /dev/null +++ b/compose/playbooks/prep_ubuntu/vars/base_conf.yml @@ -0,0 +1,10 @@ +--- +# Переменные конфигурации +swap_size: "2G" # Размер файла подкачки (по умолчанию 2G) +reboot: "yes" # Перезагрузка после подготовки - "yes" или "no" +update_pkg: "yes" # Обновление пакетов - "yes" или "no" +configure_firewall: "yes" # Настройка Firewall - "yes" или "no" +docker_install: "yes" # Установка Docker - "yes" или "no" +dns_local_server: "10.130.0.16" # DNS сервер в локальной инфраструктуре (Для внутренних запросов) +dns_cloud_server: "10.130.0.2" # DNS сервер облачного провайдера (Для внешних запросов) +local_domain: "stage.co-work.local" # Локальный домен в инстансе \ No newline at end of file diff --git a/compose/playbooks/prep_ubuntu/vars/secret.yml b/compose/playbooks/prep_ubuntu/vars/secret.yml new file mode 100644 index 0000000..5e0776d --- /dev/null +++ b/compose/playbooks/prep_ubuntu/vars/secret.yml @@ -0,0 +1,89 @@ +$ANSIBLE_VAULT;1.1;AES256 +39396461316337366265626162636265633531613738633230653339346336323965643935363639 +3336363265366535316366373161626634626330623134330a373338313361633863346333306662 +31663962663630336139663866353065353162616332356163633436376562336261393237353065 +3838663034613834640a663363373838623935333733646139643633386133323634623537666164 +35356532656533663737613034636336636465373838333563633239366562376164383834336138 +37323066626166313432343137636563326533613132343133623134646264376131356462623965 +61306662356534623065386336646534373230333132336261626138356533316162363265353135 +34343263306166633161646531633338373132313939336162373965333163636263383230623762 +63313162633738623065326631666438386263393262623930313263306135326633363737373439 +65656534393637363661313132346166613666373462306430656137313262643231656362326532 +39303134633735396264363839643832373063666561613739613535396135353563396634376263 +31393936366337303237323661373061653434343064376438643066643962646264313832613664 +63303132373331646333633032383064663461616562663064393161666162306365653538666233 +39633361343034386639633335353261383433313432633332633665653462363836653332386565 +64316238623037393763643035366135353237343539633336663335393262666164356134373638 +33303263663231623836656539643539653835656533303430306264623436353737386135373534 +37616363386436633932353466626365373739343032653464636536663334613862313065653136 +35623863326634613566626265393565373531643939356433333230613135316130383930346261 +34303135383832353138623232653831346330633030346164646464366230343130336366616636 +39656534623061326464616639336139313963396631323632396437356438363564363036333331 +34343135623932326563393034643432663264656565623735666534346537646566393531393933 +61636362666237376161666333613333626438613766316635623765353333626639363262343532 +65303961616335316134353161663933623836333636303263623230373461653161653866333465 +30663935396534363164633739623130623736356266656163333838653262363935313961633730 +62363266353665383665643734313965333665313339366636313533336664613563366230333639 +35636233626237396130613263303664626136373562313663613337303765636433376434316532 +62386632376639353639386430663866356438383239663238633162306236363838626637633064 +61613232303465613166353066386462663063303133636363393938373736393939653636396666 +30343262623261616138313339646266363839313739323365346430653530333161313034623766 +35626465313037646363633366626166363330646338336563343537636132666365383336363132 +62373562656664666235643365353432333836386639333133613834313564356132326536663265 +30623865336666363162643435303530353731356137376536613366383062336637663634386434 +37353632366436383263653563646633353939623865343335653461373233316539663230373438 +32376431393463326362623134383330626364326136646234313639666261663437353262313336 +36636432386464316561333733643531663432396562633230313232333732656264353463343065 +64346634343462383765623939373438336630643534363163613438666232636635373461373335 +65663631643362316432666464646130636664643132393636643135373137323066343034663430 +30396334303966393461346537316664383839316635386261393032616234353435323933613631 +33303162306538656138356130646136373964346134643138363939663838653763396364333662 +61386639383633333135643239313136643065663434356365333231313436633634313062336462 +62303538626538646465373263316430376437386334653864363561623562363733636131356338 +35376164376530323131333632323335373861386639333135356266633433306334356631323166 +34333066323261613136616435336563363063353331663737626261336137333430323464623865 +38643435373764353864643134613361333130666363386366323362383432633630613334363439 +39303031376231303538633432353465653065303462666165623065643964613232303939393964 +39326165366237333337656335333165333837626665656361353138303531346366356466346366 +32656339333165663731346162653061366235373137316335613764333438366562386363376263 +63353030333539376561326537323236336337363862623464393039653465613064633165313363 +30636534376132653165383064636336653635396232663733333333316131383537326236386334 +37363865393534633739633961326133356638316131336433366636633334333231313066363961 +36616532643030326532373630333336313463363434326463636335303961373763313261633066 +38633631623437656162336661356131646232633337646437666533653965323266353030383232 +32373663353166306336383563333131623661306266646265316336316563306139613264663338 +30373436333838643331643631393265316330343133393139363730653536386161346430383930 +63383439656239393338313131363465303031623232616134636638306439336531363632633935 +64323137313136343730366639306637626136313366636238363264653035636462643130656236 +39363965346633646662623036626461373134643130333261646234663839646265663461623531 +62373933323636333936666434633739356664346139316664323765306461363334326635633135 +32626634303238333336396530613934663462383335356632363762623534633531396339363336 +65383732313562353632316161666639353932333234393163326232363639373731393261626132 +62646436306361373166306536363166346438336234383364373161366536613361386365666666 +38373837323638373434313633663966386138333531313433313033666564656433386530373062 +62383165626239373939643464633366336665616164626262383930663066363732333532623333 +32363735343461303038376339333037333535626364333563646163373130363739373330626264 +35383831323630316237346135393336636361313239393035353630313635333830396138313534 +37303635636332313834323335373538333237636262613966306432363536333135363938393864 +61663931343165383432333630366238653461373139653038383231366331653732356430623536 +33663065393732303166336435336361373533303264353464346130326234383664306662636532 +34393032373139396536396662646636396435396139623364386633336162656538336432353334 +36396439323639313936626636376431383837663036316661356537326466643539336562613032 +35373335326364313461326465333761356439663831363033613164333261386131346166356334 +36373038303033386238353833383562633166656132656665626165336566323164353864623930 +37326132343238353635396262653161386562363261373866303132383135353433373738366132 +61613631313866633161646463383938313562613038356431633665663365653134353938323061 +38653534636537616661396664393631326363313436373762393336326265666630303330653763 +33343361383961323064323232366262393039666663366639623330353061643134353837643232 +61373562383433373565626237386639333236616436373933396635383333373966393133373161 +65373237393437613735383838343062333631336530623337376637363534363135393433353033 +66343339626130343830306339623466653630656534336334323730333863653062363165393835 +31633739316639326637303137646466623864333238313766386331313934333461663937623633 +39376665343761336235313965623832663962383138613137393963366464396464373866613035 +62383238653030363333373439366239376338373838643062303634356131306463393632646133 +33613739393637353466636433376363636162373564616164643066633062666536303139623261 +30383534616161633365613130303438353430663339343430383135663161323363343533366636 +34313932613034633330396537346638326138643164306136643535663036306463306366376134 +35353631396564393136616437373530663730326134343332376663306663633963663330333839 +39666531613938306366323438316566396361623434353464643839326530626637303363346664 +34303862633664363435 diff --git a/compose/playbooks/s3_server/README.md b/compose/playbooks/s3_server/README.md new file mode 100644 index 0000000..83bcb5f --- /dev/null +++ b/compose/playbooks/s3_server/README.md @@ -0,0 +1,4 @@ +====================================================================== +Playbook information +====================================================================== +Плейбук по устновке и настройке S3 хранилища Minio \ No newline at end of file diff --git a/compose/playbooks/s3_server/ansible.cfg b/compose/playbooks/s3_server/ansible.cfg new file mode 100644 index 0000000..20d7065 --- /dev/null +++ b/compose/playbooks/s3_server/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +ansible_managed="Ansible managed" +host_key_checking=False +inventory=inventory/hosts diff --git a/compose/playbooks/s3_server/defaults/main.yml b/compose/playbooks/s3_server/defaults/main.yml new file mode 100644 index 0000000..11163dc --- /dev/null +++ b/compose/playbooks/s3_server/defaults/main.yml @@ -0,0 +1,9 @@ +--- +# defaults vars +# ansible_python_interpreter: "/usr/libexec/platform-python" +ansible_ssh_pipelining: "true" +ansible_user: "gem-admin" +ansible_ssh_transfer_method: "piped" +ansible_ssh_common_args: "-o StrictHostKeyChecking=no" +ansible_port: 22 + diff --git a/compose/playbooks/s3_server/handlers/main.yml b/compose/playbooks/s3_server/handlers/main.yml new file mode 100644 index 0000000..c09dec7 --- /dev/null +++ b/compose/playbooks/s3_server/handlers/main.yml @@ -0,0 +1,5 @@ +--- +# handlers file + + + diff --git a/compose/playbooks/s3_server/inventory/hosts b/compose/playbooks/s3_server/inventory/hosts new file mode 100644 index 0000000..12f67c9 --- /dev/null +++ b/compose/playbooks/s3_server/inventory/hosts @@ -0,0 +1,3 @@ + +[s3-host] +cw-sya-store-001 ansible_host=10.130.0.12 \ No newline at end of file diff --git a/compose/playbooks/s3_server/main.yml b/compose/playbooks/s3_server/main.yml new file mode 100644 index 0000000..a9dd889 --- /dev/null +++ b/compose/playbooks/s3_server/main.yml @@ -0,0 +1,16 @@ +--- +# Установка S3 хранилища Minio +- name: Install S3 Minio store + hosts: s3-host + gather_facts: true + become: true + vars_files: + - vars/base_conf.yml + - vars/secret.yml + - defaults/main.yml + pre_tasks: + - import_tasks: tasks/check_os_version.yml + roles: + - role: minio_install + when: ansible_distribution == "Ubuntu" + diff --git a/compose/playbooks/s3_server/roles/minio_install/README.md b/compose/playbooks/s3_server/roles/minio_install/README.md new file mode 100644 index 0000000..eb9c2bd --- /dev/null +++ b/compose/playbooks/s3_server/roles/minio_install/README.md @@ -0,0 +1,4 @@ +====================================================================== +Role information +====================================================================== +Установка Minio \ No newline at end of file diff --git a/compose/playbooks/s3_server/roles/minio_install/handlers/main.yml b/compose/playbooks/s3_server/roles/minio_install/handlers/main.yml new file mode 100644 index 0000000..7479ceb --- /dev/null +++ b/compose/playbooks/s3_server/roles/minio_install/handlers/main.yml @@ -0,0 +1,4 @@ +--- +# handlers file + + diff --git a/compose/playbooks/s3_server/roles/minio_install/tasks/configure_minio.yml b/compose/playbooks/s3_server/roles/minio_install/tasks/configure_minio.yml new file mode 100644 index 0000000..2729aeb --- /dev/null +++ b/compose/playbooks/s3_server/roles/minio_install/tasks/configure_minio.yml @@ -0,0 +1,191 @@ +--- +# Настройка Minio +- name: "Check packages is installed" + package_facts: + manager: "auto" + +- name: Configure Minio + block: + - name: Add user minio-user + ansible.builtin.user: + name: minio-user + shell: /usr/sbin/nologin + password_lock: true + + - name: Creates store directory + ansible.builtin.file: + path: /s3/store + state: directory + owner: minio-user + group: minio-user + mode: '0775' + + - name: Directory permission + ansible.builtin.file: + path: /s3 + state: directory + mode: '0775' + + - name: Creates cert directory + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: minio-user + group: minio-user + loop: + - /opt/minio + - /opt/minio/certs + - /opt/minio/certs/CAs + - /opt/minio/certs/{{ minio_external_domain }} + - /opt/minio/certs/{{ minio_internal_domain }} + - /opt/minio/certs/{{ minio_external_domain }}/CAs + - /opt/minio/certs/{{ minio_internal_domain }}/CAs + + - name: Copy external RootCA certs + copy: + content: "{{ external_ssl_rootca }}" + dest: "/opt/minio/certs/{{ minio_external_domain }}/CAs/rootca.crt" + mode: 0644 + owner: minio-user + group: minio-user + register: ext_rootca_updated + + - name: Copy base external RootCA certs + copy: + content: "{{ external_ssl_rootca }}" + dest: "/opt/minio/certs/CAs/rootca.crt" + mode: 0644 + owner: minio-user + group: minio-user + register: ext_rootca_base_updated + + - name: Copy internal RootCA certs + copy: + content: "{{ internal_ssl_rootca }}" + dest: "/opt/minio/certs/{{ minio_internal_domain }}/CAs/rootca.crt" + mode: 0644 + owner: minio-user + group: minio-user + register: int_rootca_updated + + - name: Copy external cert + copy: + content: | + {{ external_ssl_crt }} + {{ external_ssl_rootca }} + dest: "/opt/minio/certs/{{ minio_external_domain }}/public.crt" + mode: 0644 + owner: minio-user + group: minio-user + register: ext_crt_updated + + - name: Copy external key + copy: + content: "{{ external_ssl_key }}" + dest: "/opt/minio/certs/{{ minio_external_domain }}/private.key" + mode: 0644 + owner: minio-user + group: minio-user + register: ext_key_updated + + - name: Copy base external cert + copy: + content: | + {{ external_ssl_crt }} + {{ external_ssl_rootca }} + dest: "/opt/minio/certs/public.crt" + mode: 0644 + owner: minio-user + group: minio-user + register: ext_crt_base_updated + + - name: Copy base external key + copy: + content: "{{ external_ssl_key }}" + dest: "/opt/minio/certs/private.key" + mode: 0644 + owner: minio-user + group: minio-user + register: ext_key_base_updated + + - name: Copy internal cert + copy: + content: | + {{ internal_ssl_crt }} + {{ internal_ssl_rootca }} + dest: "/opt/minio/certs/{{ minio_internal_domain }}/public.crt" + mode: 0644 + owner: minio-user + group: minio-user + register: int_crt_updated + + - name: Copy internal key + copy: + content: "{{ internal_ssl_key }}" + dest: "/opt/minio/certs/{{ minio_internal_domain }}/private.key" + mode: 0644 + owner: minio-user + group: minio-user + register: int_key_updated + + # - name: Set owner minio-user for /opt/minio/ + # shell: | + # chown -R minio-user:minio-user /opt/minio/ + + - name: Change minio config + template: + src: minio.j2 + dest: /etc/default/minio + mode: 0644 + owner: root + group: root + register: minio_updated + + - name: Enable and start Minio + service: + name: minio + state: started + enabled: yes + + - name: Restart Minio service + service: + name: minio + state: restarted + when: minio_updated['changed'] or + ext_rootca_updated['changed'] or + int_rootca_updated['changed'] or + ext_crt_updated['changed'] or + ext_key_updated['changed'] or + int_crt_updated['changed'] or + int_key_updated['changed'] or + ext_crt_base_updated['changed'] or + ext_key_base_updated['changed'] + +- name: Configure ufw + block: + - name: Allow minio TCP ports + community.general.ufw: + rule: allow + port: "{{ item }}" + proto: tcp + loop: + - "{{ minio_server_port }}" + - "{{ minio_console_port }}" + when: "'ufw' in ansible_facts.packages" + + +- name: Check server port + wait_for: + port: "{{ minio_server_port }}" + host: 127.0.0.1 + state: started + timeout: 5 + delay: 3 + +- name: Check console port + wait_for: + port: "{{ minio_console_port }}" + host: 127.0.0.1 + state: started + timeout: 5 + delay: 3 \ No newline at end of file diff --git a/compose/playbooks/s3_server/roles/minio_install/tasks/disk_layout.yml b/compose/playbooks/s3_server/roles/minio_install/tasks/disk_layout.yml new file mode 100644 index 0000000..2eaf29f --- /dev/null +++ b/compose/playbooks/s3_server/roles/minio_install/tasks/disk_layout.yml @@ -0,0 +1,36 @@ +--- +# Разметка диска +- name: Disk layout + block: + - name: Create directory + file: + path: "{{ disk_mountpoint }}" + state: directory + mode: 0775 + + - name: Create LVM volume group + community.general.lvg: + vg: "{{ disk_vg_name }}" + pvs: /dev/{{ disk_name }} + pvresize: true + state: present + register: vg_status + + - name: Create LVM logical volume + community.general.lvol: + vg: "{{ disk_vg_name }}" + lv: "{{ disk_lv_name }}" + size: 100%FREE + when: vg_status['changed'] + + - name: Create filesystem + community.general.filesystem: + fstype: "{{ disk_filesystem }}" + dev: /dev/mapper/data_vg-data + + - name: Mount up device + ansible.posix.mount: + path: "{{ disk_mountpoint }}" + src: "/dev/mapper/{{ disk_vg_name }}-{{ disk_lv_name }}" + fstype: "{{ disk_filesystem }}" + state: mounted diff --git a/compose/playbooks/s3_server/roles/minio_install/tasks/install_minio.yml b/compose/playbooks/s3_server/roles/minio_install/tasks/install_minio.yml new file mode 100644 index 0000000..24db5f1 --- /dev/null +++ b/compose/playbooks/s3_server/roles/minio_install/tasks/install_minio.yml @@ -0,0 +1,12 @@ +--- +# Установка Minio +- name: "Check packages is installed" + package_facts: + manager: "auto" + +- name: Install packages + block: + - name: Install deb pkg + ansible.builtin.apt: + deb: "{{ minio_deb_url }}" + when: "'minio' not in ansible_facts.packages" \ No newline at end of file diff --git a/compose/playbooks/s3_server/roles/minio_install/tasks/main.yml b/compose/playbooks/s3_server/roles/minio_install/tasks/main.yml new file mode 100644 index 0000000..d1619a2 --- /dev/null +++ b/compose/playbooks/s3_server/roles/minio_install/tasks/main.yml @@ -0,0 +1,13 @@ +--- +# Разметка отдельного диска под s3 хранилище +- name: Disk layout for S3 store + include_tasks: disk_layout.yml + when: disk_layout == "yes" + +# Установка Minio +- name: Install Minio + include_tasks: install_minio.yml + +# Настройка Minio +- name: Configure Minio + include_tasks: configure_minio.yml diff --git a/compose/playbooks/s3_server/roles/minio_install/templates/minio.j2 b/compose/playbooks/s3_server/roles/minio_install/templates/minio.j2 new file mode 100644 index 0000000..c3d5f15 --- /dev/null +++ b/compose/playbooks/s3_server/roles/minio_install/templates/minio.j2 @@ -0,0 +1,6 @@ +MINIO_VOLUMES="{{ minio_path }}" +MINIO_OPTS="-C /etc/minio --address :{{ minio_server_port }} --console-address :{{ minio_console_port }} --certs-dir /opt/minio/certs/" +MINIO_ROOT_USER="{{ minio_root_user }}" +MINIO_ROOT_PASSWORD="{{ minio_root_pass }}" +#MINIO_DOMAIN="https://{{ minio_external_domain }}" +MINIO_SERVER_URL="https://{{ minio_external_domain }}:{{ minio_server_port }}" diff --git a/compose/playbooks/s3_server/roles/minio_install/vars/main.yml b/compose/playbooks/s3_server/roles/minio_install/vars/main.yml new file mode 100644 index 0000000..fa2fb4c --- /dev/null +++ b/compose/playbooks/s3_server/roles/minio_install/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file diff --git a/compose/playbooks/s3_server/tasks/check_os_version.yml b/compose/playbooks/s3_server/tasks/check_os_version.yml new file mode 100644 index 0000000..2909c8b --- /dev/null +++ b/compose/playbooks/s3_server/tasks/check_os_version.yml @@ -0,0 +1,15 @@ +--- +# Проверка версии ОС +- name: Check OS version + block: + # - name: DEBUG OS version + # debug: + # msg: + # - "OS: {{ ansible_distribution }}" + # - "Version: {{ ansible_distribution_version }}" + # - "Major version: {{ ansible_distribution_major_version }}" + + - name: OS version not supported + fail: + msg: "Operating system {{ ansible_distribution }} ver. {{ ansible_distribution_major_version }} not supported" + when: ansible_distribution not in ['Ubuntu'] \ No newline at end of file diff --git a/compose/playbooks/s3_server/vars/base_conf.yml b/compose/playbooks/s3_server/vars/base_conf.yml new file mode 100644 index 0000000..b453532 --- /dev/null +++ b/compose/playbooks/s3_server/vars/base_conf.yml @@ -0,0 +1,17 @@ +--- +# Переменные конфигурации +# Разментка диска для хранилища S3 +disk_layout: "yes" # Разметка отдельного диска под хранилище S3 +disk_name: "vdb" # Имя дискового устройства для разметки +disk_filesystem: "ext4" # Файловая система +disk_mountpoint: "/s3" # Точка монтирования диска +disk_vg_name: "data_vg" # LVM Volume Group name +disk_lv_name: "data" # LVM Logical Volume name + +# Minio +minio_deb_url: "https://dl.min.io/server/minio/release/linux-amd64/minio.deb" # Ссылка на deb пакет minio (Проверить перед выполнением наличие пакета) +minio_path: "/s3/store" # Путь для размещения хранилища minio +minio_external_domain: "stage-store.co-work.ru" +minio_internal_domain: "store.stage.co-work.local" +minio_server_port: "9000" +minio_console_port: "8443" \ No newline at end of file diff --git a/compose/playbooks/s3_server/vars/secret.yml b/compose/playbooks/s3_server/vars/secret.yml new file mode 100644 index 0000000..4de70e8 --- /dev/null +++ b/compose/playbooks/s3_server/vars/secret.yml @@ -0,0 +1,608 @@ +$ANSIBLE_VAULT;1.1;AES256 +65343037653138646434613537663731323031343366663561323464663663383561313536643263 +3766373432313761636239383962356334353739313036340a653430326666393061646465656266 +65313332323261653132323739363430623936353831663665343861363439353939666533396633 +3632636233306565610a303963636466303135393537643830366138656664343630303563613838 +38626236643538653261373332353436393739363930613762663063613164346536633133663339 +33646330343466613762316139353561626564323063633666363932623464616337323234343764 +39663832373636656634346631316636316530663836363262613264663234323132353462616434 +61366433383430386165343232353030396433363836346138313734626264643132363034623236 +65663231643832663565653061343738343931316166396566356566336462316638383662336662 +39373162616136636532633261626664336161333033313666343532393638356532343531633637 +63643962316430326233633239616661316438323236623536626466616333306134383638623131 +62373264613131323135316661373931343862646239626636343965383566303334393137313363 +63353638366537333630616461663464343131343765633465643735326166376439316238653937 +35396531643739643835666632373339626264633331336135613161356333353663316437663138 +33623730393764333738626530376434353733663836383261636230363336303533366531313336 +32303564633030656466313838393733313064343532353632656138353863303938646234383834 +36623238623465323830613333666130366561623735626630643035633934333530366234393935 +30363762656362386239363636383334636437336134373238336436323139656232653736393236 +32616661623336333138363835623437323866336235656563613536656536363531353039643536 +36343137363135623533323733663961643537353161373666333063316430623031353364626131 +32633564303032363063373962623631666437363562343837633561346265333539333434346239 +62396265306664343562653063383633366130653738363764653539336562646639613937633633 +35656430313365373230353663633461646435346139393736333833343164646631663131663130 +38336332636434363437336139363361303063313333393038353766363833653263616162313139 +39633166356535396437393861343337316163613761626662316164303863386630346439323134 +61393963633834336532343236366537366431653038366639313536653937383264336161393039 +35376366633530383734346264623639396137323437333662633438623366303830306336396434 +63323935346231323533656132626166323039623334646365356664303738383538393038636639 +38373439656231323831353665666265363862393131343737393333383162303739396336336632 +32323232663633363032383039633831656537616635623637663536653832303365383333333131 +66396630316166386262383361643833366635643033313933303933656162633632373330363730 +31393165336434333133313931326362373139376235666666373935303264653534396264346239 +37303265663935353566616534643635306563663632613032643132653234333536653163623865 +38313232323165323731333432343432373933313062626163346265393864326662326632326363 +30356561323334393039323132313465633133306437656665633563303838663639316162313239 +66613438343332646262343335666635653836613232643464353234383462306131393764376164 +33393563663234636338313233643962383139626437303762613762616234303833653764633861 +62613365383231633637646539363066383536393737303638396238383134306664623230613961 +61653364666231616431333330646436383838636439323336366634326134396435653338643135 +65393635316139613838386532343762336230616366643137343834633638653539623736383432 +34643437643834363531313666373131373934346434643431653666363933656662373161383066 +35373965353031336266396135343065383632653466653231616164303339313332366164326136 +39313638363163653666326137366139653435383963386134616135356263336530383463336161 +31613564393637323736313263303162386434373235313165376633616332323230343664323437 +61373934623961653266623761373135623239393236363466656330323663383631323435666161 +33663632363962303436313761373230346538393766393561386662366161613366353235633037 +32363063633062396338633139616437323338623633366134323236633334613333376665386232 +64343466316561633162353036323536393938613238356431323435316566383861333161613763 +38663964373265353765396138646361336134613365313038383931626533383361333966333966 +36396633643339633936353363326464346432393138343264386365653236366332366664376430 +66636461313037353764316362666433616137353939633634343465666630613436306366313361 +66313263623566323436376361383466323233323030393062333764643362356339383432663665 +64353030643362626163363965333132623765393663306539363930353863313061306335326633 +35656564353562386634666261643036626632633162346165363463353235346635633736356539 +32393039646432613835303065656433343333396264316431653534613936613362306239646538 +37373738373931326531653439333364663033663631383631653738383666386631343031663162 +33633166653765383235636464346164333835366332343835373061373638663438623635343465 +66656261663566643962313832316335656237346566353565333239656230356538393632636238 +64333265663361326333666162373566326132393162643065363334626264393666303664326439 +31616239633566383762363339303530303239613562333161333665343038326365363735343233 +30306263306265343264643437373662363463626465336437636463393731623738643263303331 +66353333666462616537363962323932646430616133336134373564636262643337633565316430 +64396339633032663963633562646531623266623765643234373266313263306134323236643238 +32333231646639323833343436656536616233623161353433653339643639633933653432346365 +32336538333262636137666437653664633063333332356538333265323135333538633837316134 +65316537333062626535643966663366636437366263633330353365353762353563376465396266 +37396566363031623334613765646633643665323239613533373432303834666661333761353835 +62316132323861323563653961386664333536613364663031666135353331336663306665353336 +33613335633939656430663833363336626531326434393036353763653264373665623466333232 +37356566303230656430346637363731623434626561376438323038353137333566333338656436 +66386463386437626636373734323035353231346163613565366436633063633262613636333965 +34393131363633643738636633306563643566396435383261363331656135313638663739353662 +37623362633030653832303035326438356436353539633032353936613263306166636538656538 +34363832356136643330363232343430373765303135316261646564633439366636303337336466 +64336432363566306334373534353464386132313266396437613963383231626637623335333736 +39356431646362646362346132653839353238356464653730363961356464353939373637333839 +35336333643036353166613139646663303733323737643631646364326533313265316331646535 +33616566316234356463336365373962633835326363313966393666393463343861393832626239 +32323235346361633261623831343234396161666239346132636239633239613363376262613732 +30636131323636356234356366633330633033343461316633376562313233653034343630323964 +34646161306630353938396633393730366162393965356462306333636438633863616161303132 +66383064336363313636343431613063643437396131323064373666643466393539653135663666 +31373734333436323831386531333033366135383165306332326431336231306132653633306663 +35313631646438613962623737386663653434656338333739316132396534366434313465353230 +65663737323831613961636531653032386261313763383130663034633463663163383162353936 +34353638376562366563656138666664626265316433396466313331373565373836333266353463 +37323733653862613766363462376130303061383064656164306438653566336630353663616234 +33666531356538343661333438666432383361343264396462316431303163333761626433333035 +63396661343334323233353163323738353365373765646139366564633664633536626433306236 +66646363396463663565386633653366366230363561333137303032643630316561356338663032 +32333461643265663532346266636335666233343834633337323461396538313862353131366639 +37386331316463303034636265396661396435373031393033666466363833653363663862333463 +37363933626530386536626135343165356562303866366438303336393737353933636666643733 +61326262643433663063623735373330303037316262393035323834333464336239323731613763 +39306530366531633566376463643932633166383434396466633630373738333135323764373332 +61356239336439353266363162383732623162353066366439643166393432663138653261353137 +63623832383237646563636630373864393334386138623335666633653765323162383737326163 +65343235313061633137333634616431326635353232636463353061316465613539393939343435 +33393134663665346164386537376162313836396633646261396234373539643939623239333532 +36303633306139386161333931366232616535316338636266346365323935343064303931373833 +33396363303435663731323436653034353764316639333630643038336431313265363435356434 +63646365336530306138663038376535306237363330303132643833663439323934343266303765 +62666235613461383862323132383565346363396635396137313131653365666437326531303632 +39343133643238393463393530636266656439343764383438666536646237346261316662623064 +38646635386165386536613464656134306464663230393966663230376336383833656464666136 +66666537343963383162613166323139346232366535386636653533353963353639326530393538 +30626565633162623765373939373865303131386434343763643138396438363863346434616436 +63303134653930346463373038666438613764396561633333316639333431656631363531303665 +30323863636563363532343232386234626666356437336463363365333137353334366164383761 +66303634306165353239356132386236313563376465383233653234636639366134663534643832 +31613364376236363434623962613038393330336336613062636336383430396230613432333731 +66393030396261343863663739393661353334636266396131336461323738363161333532363665 +35623833353435653132313630316537646533616639303234633235613166353531376164663832 +38633864613765356166613930363762376339303430653339333335333230323330393165333635 +63643066616165633134396636613965653462393735383236383238653761643562343065376235 +66373831343536313639666237613761656539653266643034353936306634356134656638616633 +66363238353066346534396334343930333065393632333739653266616632333431656134613430 +33393763313933623738636439616435363935613534383537646330373166356363623262623631 +61343034343262343165633564383839306231313237656135656235306266336139383231393733 +37333331353661636265313430366334336137356631346339376164646232626332616162623432 +63633434656339303232336564613536643133393632646235306362363739363133346161323037 +64363134396339343239663139616362363265633235356238303639383261313336613763333338 +37633362643166636130633563613564303730616264306237356561666435666532616535363637 +35336162313831306261333034333863633937323130393936353237626664626261663262303861 +65663436633634376561623235353965333139393236643761326338356334393562373663373139 +36336566393962343830356139323763616434323565663462333061386465313136343664653161 +33663665633464663861616561353563363362623338623734346165646662633539663330373330 +34613835623835626633646434643561303131313966376631366162393962353137303537356666 +37613162316465346537656437373238306335323364333738396132366634633430643132663939 +63633164613064663730323934386661613937656338636166623036386230386332333536343833 +31663730623238643033356238653430663064373231313239643461336639333232353836336332 +32393965343831623362393261373334643334303165353661373062626230353362636537376136 +61333832646566373439643836316532653366636661613335646134363032633233313539303337 +38663233306463333135623738626365666466623630646132623962343966323939343532326139 +34306134613661333962323230393232623765356166656531633061353565373961643363326165 +33653338313561353562653133373632386461303361663338373939616262646337393665393238 +34653333366461623961373566616537356363396636653964396631353335383262653834373832 +62333035346330373534346635323437613536666161396161313437616637363765353666623661 +37366562653535366434376331383963343566386461653831666333326331363236346537626232 +65333964623064613734393162396237326464313062393331646463616661653436306465386562 +32303034633264636136323739343666646662363434623265663561303032303235616362326237 +39643633316531653261393931366630313835356638656132393934396365643139613639336235 +33633166633439336164353861633738383734636338343531663530663439333734656637356366 +64626439313437666665626166396131373161633932336139633938383934653431633833376532 +33666433363162303865356437626635613666646237333364623466666638653265383266303464 +31386530353466363138316261616132393261373364666236346366663932326464373932623831 +62623163313264303731326335313034393537336665663439303230383531336364383566383534 +38393262353663333762333861396662613136343333643431346465306466323433326561636636 +39343137323863616365383431353434613032396461626632386263636365663135626166646265 +37343936323364656133636137373035393136346361343965373364346462356436346330356266 +32343330346236376539396561396536346633396132373730333636633962656664393339646431 +32353634373632343339633836653363343535663564653432303935316664613563643033393461 +30656166663238646662643865336636623463393763613934636531383430663163323932313435 +38346261396161623836373262323136316433336263613733396331303864313430336339623131 +66613635323234373631323365663837323561313230633335643933366633653465653665306162 +66613034303937386565613164343937396261306431643064623161336335383731613465323730 +32613030303761373137636138343036623366333165336165363930656162323634313334333664 +66663361353936646135663738373931643032633866363134383631383833633935323139383235 +62666234333661343335623163333436333533313562383133626566366362393830333463663134 +38396134356335643837313238316138373634613436343338336635616562303662643932373034 +30666162353061323436633162666136316333656139343236393937663839643339356131376132 +65623538373930656339393365666139396633653061346537396265373961666632363866353332 +32376366663433616336613962333331313935323061333837303930616137326530623666643438 +66336539616434623161326630626361643938303635623838383639306261396339646432616132 +35323131663431343266383730313139633531363863653838343763383335313135386130626463 +63376565353330333332616538656135616162346232636330323161393465303832316334356139 +65623566663839633734623937393639386631356131623462346136643636643732323964623133 +30613465653136353036613238663134383338376366633365396565386438343030633435333337 +64656237326137353561323834303131623366393164353831303637663434356661623832346262 +32373664386265386363373136623934643131333230343131376538363765393732376232363134 +65353864653338396339666139346662366565313064343231663131393066393336316338343339 +39313333336566643762376233373963363666363865303861366533633230643266666436373962 +31303166323739613566386532343962663863356666646539346434353663393336326632313666 +37376133646661663865316233316335306439643637343438393966396236373066333563633761 +37386164393830353164636565343835613332366163343664376435653135313630386130343362 +34663339633933303635623734393233353537373035316564643165643430393531633739663266 +64343638363234376634616330386161313932376361653665373564343431386464383134383839 +61396636346633306335366232306165643533636364623130343933666633323031353135356266 +64666263306432353738336634643536633430366663626436636336653661623165383730623937 +38313530613231623465343636663434613831376637313064313439356664663565326136383363 +30653962316139373564633363623666363738666334623338363934363062653636636463366334 +65306232396262623166643463343733306633383034306564333762633332636264316632343537 +30366233643662303263396231636561356266656230633835373164353133633136376132386537 +65366638666166303437353730343136333230616531613938623433303865626437643930636466 +37393161353135333339346433373531633561373534376666343535366232363066613830646234 +39376432653930303231323766313937343066363535336165313862613334636665623938663962 +30373638376130653832653134373030646538376330643363666666333862656136663963363439 +63336631346239353139633334396666616463313331643835303762636661363035353563373765 +62383437633735306465346463643963343333653565623838366132636335393765366337663961 +34393564646636623036353933386462343939383537636337636365663161626130353732316538 +37316261636134623734666235333934613566623065393061303637633265633633653464336534 +61316630313961653731356535303531383634656439356338323234643937313530626365336364 +36643530326139316239636431323938636430303361326563336433326439663965666461656239 +63343031343262613562356432663930386231366139346461363363613936636163653533333539 +63363836373638633639313835666630646632323231633934636231323061663066633663616530 +38356437323763363632653831393331633731313732336237633438633734313663356535346665 +65616431353735343135393434646163313866653634623530363961613932303930306564323937 +63386134656636656232613562613839353966356236383032333433623430623434333536376664 +38646331303865656230373639626237393232653838613562313239613966666631613736376434 +39313761326638636236663931623431373363363639323535306137373732616233616436633965 +37653765646638316366623135356232333836346132376161383437333963383939633030336264 +66343933336238663061356138333839376630613861396638623237663063313635653766323631 +61336364383163363637323566343934656438623766393839336665316638353237396239373834 +36316634323634366362326232663438633230646563303464356336326534363361643035663061 +62353032376334396266343164356266643538666665326632336531616563653262316536336662 +31373533333138643964323632363964303532336536323035633465633466643262313035306135 +34323662303461356361313362376339363730643432306263346132616231363563666566373338 +36363836383730656363613237323764636532643539313465636430343263656136353862626637 +64656264633366306133396333313331363266303534393361383532653733663138306137313333 +34633535393364306639636430373035663832643762653738616464646365653032663331333766 +66343939323732363064386130303930633533386335303862386238646565633433383535653430 +31393463353162643063386464383630663764393037316266646431356363383466373761363736 +65383532306133613131633737393437373463353066323730666266616233303433643465653832 +38313865303766663931653365306261306137626264613936326539323361363237626630363064 +39613234333937333730376661373435623961363339613834383230653664333834633162396533 +66646664383537653366613431363236366232663764656534643264343763356461333063653636 +30666230363431636535343764633834376537386531616165353061653864303938663039636138 +32373961303639376262323962346337313134346264326233346533306630636631333431353431 +38646535303732356533383133336461303631313133323762386238393236663533303366343564 +31326265653531633630343832373561663164333565303735613765613137303932643535363531 +36326261643366663162663637613061393062336162303939373565323237336465313664333362 +65616233336439373764333463366235663834383766343038366666316131383764393066373738 +35343133373430653335633032353561386136323831616637386334313838323462343339663362 +35636438303935633231636439666438383561626330623366383262623131613166623534333364 +35313235666631306431353130663966613836366466393066303066376337623731646330313139 +64616132333735373631656532643231356232333962366366316631633562636361396139633765 +34336161383632323036303239383161653233323863323532313561373931633332396164393437 +39343664303961376663646239383936636566653463616131613364643035323433343334646562 +39316261633536323836643966366166363832383364316431353239616566396333653935343062 +36353363646165383062616463623235353030383163343236323565383665383238633466636566 +38353335663066376431616162333332303165616663623332353939613435623438613931393730 +34623161336166393230663231383864336161373234343666313765356536663937643239353363 +37643430313664323263636165396362616139393430643136393338653233393433383133616639 +31346463633634643462623736613431623334636134366432613862376433333031363836633436 +32616239616333653031653337383832336139626564643165393639393634643062623665346336 +31356636656134666335316139366664303536396136393631643330643536326539623736333633 +63316438633466393434393264316163626634323763353033613236386138363564386133393966 +33376531326337333865386633666361366437393139616433393566636632383039383362366239 +35326438633166353465366264643765336137656632356561363531363239303665333736366435 +31653239373864663465326230613032323530363836356363333565393637306664383337643938 +36623064363933383535366364386265643465386539323934613435346164626130333061653138 +31303265623766643739646565303564626333643363643764343433313439316638383335373232 +36316531353364303932323532653265613962663037353530386634373733363039326464393137 +63313561646364393133613464343135326537366639623332343232343066613864393465663362 +63393030336534393834643738336561636564636531393964663534643539333132646638613461 +62383865633266373762656538623365633631383965623365343037303639323631393138636462 +63326234666335333838656331383138393465323037366330356431623037356166366430393563 +36376465333061653164616161383836343333626239623537323564353262646333303637386531 +39643862666265663637666263323630623039313932306561326631336332666237653566636337 +32313238656336303132333938363062363238376565646531323161353631396238363434643866 +33633432303163343662323435356137616333646365636234303561393565326664623837353861 +66626461333163396233343837653432376431643730663931636335323336656162393030653631 +35623530313035666438326438323038373938323537316665383537333262633932353937373831 +63303336376661336338373333656566353232336239666664353237356362313233613366656565 +37303662306361346231306430353937376133633164363034613232663930313132303461383430 +61333963366433623164393836613637366136663033363734613130653761636232666332343230 +31363062316531396131303431636563303966613863333566616439366431613933363338613661 +62396665346534666465376635613866386231333235636630343366313561353635363862376361 +37643933336234313332313334333466633439306230636634643866303463303530326237636263 +38643864313533666564633832306663316465343730353064306536613232363466323235346137 +34663334326335633138316130376566653137363866313633386136383763303133363431643761 +36303739313064323036326561656466663738366236373132336661633134346534633631353561 +35366133343962343036326535346137636437353635323733343634653437636531373930653266 +66616163633231343430646437326438323038613939623132363137396462383862353365393136 +61613834313561653637343936323931363735356133366366396535363261343262316638663336 +39623036333033323861353961366631646361303837623032383635613531393834313036366631 +66633166613637646366303861613966656231616139316434613761626133666161393832326166 +37303663356530376137353834353933373264613330663231663261623865303065306233666664 +37313361393863313363626238313534633136366265666561393138316566356365303065303331 +38336135303334653061663837646231643332633535623062386139656562346537316661346161 +32376465353266316537613136636233363566313762396265656538373433653933313232663338 +66633130383836343930303865623262656338306361363234386137353038303536663763336139 +34333938643137656535666561656536393332386531323736313261376634316361393130313933 +38393666303563383238666666323061633139623065663661353738313564613065303838386137 +39353564653733666333616461353338303432353133333366363539666561656632643939646430 +38356664303164303862323861623362356362616231333761363238623764616463353539633439 +31386165316164636534626338396536653138346165613338623530393634623862333564353166 +31353531663265326531336165653536333730306666303465376136343966333565386235366365 +62333637333933316533623264363736306134643135343130663465343133653161346134336439 +61383262346663383332356537356165316661613964386666643835633566396231386538303465 +34646231303035653238303832353632656566353137643834346364643333346537613439353161 +38646332643733313139376238333230613865376231383762646237633733373763643766666261 +31396438333339323862333439326138373061363837623937356162363166323064613161386432 +33396663393230333537393138646262663065343865663463313333616235386338646165653765 +34316334353366613865663531616662663431303063316333326331313531666461613664363831 +66393164316365336165373639623938396338383565656531636332393266616230633465646534 +30623831353462396334616635626639303035346561613662326432303565636435373332396462 +64633830376534636533326633303462613637306339383832653065313235613937363266333932 +39633937333937326335356464383037366436396437646566343564633033633438666366306564 +65616236616331363030353366383136326434313434383163663565396135666334306130373438 +32663833383139353362663737383361386138656136623334363636326430666532326331353065 +31323832353066613866326237616339396332663633366263303037356138623635353134643063 +66303531633936353631373061626135653963336634643064316366313664313265316638373631 +30393136373436316535666136623732313830623563393232313166646538313734303962666566 +32313231376231633933373863313832386561623865646565316661373761666163303363333130 +34383861326364373838396137356239346133336662386631356565633737636363346664316437 +61663930643262646337303231393231626133636363356336313762356337623265366564303865 +33633231313566366332303732613235626465346133636538386164643237613661633963326539 +66366633393764393337323264343132316531373962326662303861333839653764656233613238 +62643231616564333665303364633430386265396664626264616236623166373162393538373763 +65653964383161326133323966303133666131323965316432616465666161653638653736366334 +61363839643066386166626561393438396466393233643432356463343163653830303532633262 +64646432653462653033656434656165643663656261336665643534363131616461376361616663 +32396261343835363863636661646632636536663032343434366538306537643862656361386661 +32653666376464383063626564353265363261663132326666326461336363666436383166313335 +62333963633163366238313061383231356161383463343935313565656662653233316434393230 +36613737656533323961316233366338663465313530656532383032666231376130623935656138 +38386261333763323733663134613030306532613234306265623230393839666137356135323764 +37366265653539303063363562633932303663343264393130613063313463386634626236626539 +31616163386538666661323638653861323365646165623832323736656535343133316664616237 +33363236303137323663346532386362343839636235363533333533393464363964386261383237 +31346662613133616137373966396533353962656237383733663364336663373831653165643530 +62643361663433666363663564316537663930323432333537363361666639373861343864323234 +36333162663066613230363735356432663865633536373165643339376464356532366664363737 +63383032643738363037636464623062383438636666626664366164633639653734323539626233 +36613335323036383738653734393634333238613463303161336663303835623936353561663463 +62343335613465393636323661323765313039376533663832373832396239666530366464323238 +66656133643839383662643865633061663034383233636435393464323139646630643933633438 +34333732393465636264646539343039643234393134343135393364663435373661633438396437 +35653463616333653236663066306661393336386262376235366436343630393033353536356365 +63663466386330633865626139383236646563373636373064653063393966626638626663383830 +36313933356333393165356565316335323533613863626235646631396663343138373739336265 +30633765623734303232363266306139343431646635373061663564373331663738646631313961 +65303866353730383934343531373364343738343934363761656334373966623435333631616333 +64336335303437326266623639396231376630663330663162366562663234366562326134353835 +34356638313862386635633038663535313930333834363164386331666136613562656234396231 +30643663646665313165393862393364313665646566306438393031306332626335643632306139 +36353962303736653563393561646136373166636233346536343037643665396538623764663164 +66363434306462353930646364663536363530356664383832396263646462636533313834363262 +32646538626138656164323934373736303738666534386562613861656361303433373938313065 +36356336316266636133393935383365623436663662643436663962373733623131353533376430 +65336535386331633162396139383238346466336332333334326663336563616333626462323865 +62393036316536666330613330663335353537646334613239373635353664396438376630363363 +38383536323238333431663761623063353839666331323439303935633066303839616534313962 +36616539363435626238626138643530333561373364613434353838356437633539303133396664 +32346534346466643031326664396662333236363137383335383138316461616461623339613066 +65613066613566303963316562356137643435306636353430336266343364376439346435303637 +34623431613039333161363030613937353931386532653065373637373762363233313666393166 +64326531303233373931343164326536343965656561646334623337326266316630646634386631 +39343331616262346335613839633239626431376462306266613762653737313535383364616339 +62333233353430313731333536356234646233666136613435343838613431616562303263396134 +30353133356337653934613539336534323135623938356130313933666236303236613366393635 +62343432353834313431343766663937306462613434333239663561636532343964313936306431 +30316335633733633265343030373866366366303964306530663764346235623962613764643662 +37386666643135363932393162663734316164306239313461653534653964366431316235653932 +35386433646230623663643931663330653632636639313235313035383863636162316465626133 +64306634623233373262326335383832643665666363643534653637343364313164636637363035 +63383730376333356438633432396438333366663962393762313130326265363462373832626434 +30363537323239353335343038363861643236656330623635323737313361333631666535656461 +38323433303461306463373238356664313230663131303464353463333433633738633066353864 +34613562316532646530383964396364323238623436366136313733663364306365656130393162 +61326631656334343062366634316235396433306139646333613437393961616234323666336663 +62343939343136396665323539306630643435313239626232386538633163393137633132643864 +63653265613665313666306438303636356664616130363131323166363134353764343461663961 +39353435306239636330653165306139336266353334633665653630363733393065633731613737 +34343137313131366461323532656664373936313737363932663439626534656266346631653536 +39396563656137623763633439623565623838313432316561613935373530323338316465386330 +65653338633631373466313436356331663131656231663932303366383536653166383434353835 +63396266616161323635666235343234333234373762393464376236386438623737356365336363 +31623033336265383466626363356162643163643339663035633439303266393537363164303630 +38396130376537333235633163396164643665623637653362373039373961343064323164633935 +38653435306266336562623737383561643439376266663836613634326438393930623065633033 +37313836383361613838633038343961316463386235376535666135353833346534323435643864 +62363166353165356461333731616162393536346434326137353537343039363166393133346637 +38363962643136383131336339363735663834626337366231346538316434376333303361386666 +34333237306166613832373163343561353537336637643662343232313635623734346466383061 +61386132613039306638356538333339353462643832376362643462383038326239363039323231 +66313362636333383034656631336536373237663231636636346366396666386238333762316531 +66396366303337383134313266336265646539646264636633353131663862353562393166383363 +64373238306161373765653037326236633538386465653064366437613235356132313061373264 +66343335646564353833303738666331376431663139616363653361383834376562353334383333 +31623837333139666236363064653661323166353031373930666232363535306635313431663763 +66343939636537376232353435626666643534393733303165333936636439653536303636383863 +31666439613937373639333935656138653163343134653139393837373664373638663036396361 +35386131346264363932386532313261646332623264343336346364306262623563643234383763 +65623830663132333264306466373932666432366564343866376439656366323939643235646639 +31356564313236633938356336663733666630383830336230313034313662333938626164313037 +32633461653761646238666232663662373464613064396133353064316665313264616335376663 +31353730623261643561653263623931643837373836633633636137393263363230306664333233 +64643832396466623535356638613538393063356133646535343463383131303830653261636161 +64616366306235333937383663363862373538343064656332323762616331326661376534393032 +62363934663235333833613237613237636663663937363564323864313563356133343432393038 +66633361326361373266666464373138353234333962306266643533356531623566616331316263 +33643462353337623332633532333762663237636264373233303235346330616437366432643364 +38393834653430306661353933636166653061303465626666363632616364616462373430316662 +65653966326334656565316630366663396164613938383666353936383039646262366230396131 +66303836336564323563396533656663306333323036323165373432633364356333323438666162 +65616431633230333535346162326362393265333361313239336438356435653462326164353763 +33326636633161656464303138636565373639363139343734656435653431626438356464623633 +63376261623930613165333732383061336132353665653036666464386135313337353866636530 +36663963313436353332613430313236643765353239343365306538663036306362333037653839 +38666539353439383639393966656636373234303866663536613363333139616138656266626333 +33313837373934366664303263613131353438613134386639353537353331636534353336396536 +66383031326531333332383435353261663439323937663433393763656435383737356434353631 +62306137373365356136396138646139636366393633616334316638653538653764363534623339 +61303033616238643633613064313330663961303737646333616533346364353362656238653264 +63333461313761656566653438666438393131663266623666326662396265316636653937393737 +38313936623031666561646663373431373366336330653635376530643034343265623962613530 +37353437656132653435323266383832313766666439376463653761343130313835633765373961 +61306431323631626631643832363161303131336439653965386331386165366534333762646335 +63383731663763356235663266376166326565363834323864313236333535393862323838646462 +30393635623839373839646166653062373432373533666137623763666239643032393063383561 +66663332666565386362306665303439373230356430366334346165663262613135613432633339 +38383562373432623362333039626164393863333963623133383734643931393033336663373463 +66323838393061646630646362366162313064656264636163373665666466333232353562386430 +35656236363532663431333964343130396432306231646434623164313965323431333238643934 +37623638356566393434313136343936353535343836333564643361313336306632663531333533 +34326636323234626136313839633763366438633330656232643563656232383731316330633666 +66306233343136383663396136616538393031386636653531656632383363633431373066356463 +32333638313963656661343736643537343665383137393430343237613130323566633339393931 +61336530366363376532613164303432343062396136623734303037633733656431346661623032 +34346363643037366265663264363833373337616664373661386561626336623736303831363265 +30393062666163386233656565376131613866666139636465343730623865323062646435626132 +61626336303463366630386363313031636230623132613830613265393037303831316464626338 +63643235666334613862303230373835373066303138363866333235646164343637636362346662 +37613731666330393931323732613139383065396266653936363233353832343431363736666433 +66303863633762643266356336633434663538306337383539636637306239623966663830636236 +32666461623531386562383731313533336234386165366634366361656563303932333739373761 +66626136626435626466373761323830343764333165393033353066333136373334313034373137 +39393066393165613231313561326639346435666434383537346230333234663162616131666366 +32333863626433383966663336373665326135353064643534623861356638346536613531373531 +38353438386262373461323363313766356635326261383036346261306361356537366563306237 +38653063613063323239386665623861303432396335643065623937396166336236623230396362 +36666137323132323265333165316464626333343832363033393831386563626233623638336531 +36626535653966343763313665623764363032613663303766633664643035653036363761323637 +31393662343237343161336361646330643630363834613632393834616436663263346538343864 +61636438626265653134343634323237323861336239613231636331653933323237633161643830 +62323062353266666638313163383965623665353962646335623266313237653862386539363230 +66323536343433653531366561636330346134303762393037313736643664623165393035653039 +36303331616438373631663032613238316362653333623061323330386364643737636565633632 +65303337363636386166333539656431393533303364663236393063653963313862303261656566 +31386339386263616336336630623863386639303765653039373963613533616334643566626339 +33666536306232393462396134336665306331383664333461363532366633613930333163313432 +64393938356535313735343239643665376665323634306134373162323366323435393164343162 +30623034613330616432356663666234383061326238636563653264626464343735313165333533 +35333230386361383137626465656536323833653464346335356439633334653964343063646332 +66316566383731313838643136313263343438313735613438616637303934396631306464396431 +39353661343339343361353838636636313531326162373335313835383934613838313139663862 +39323136366639643961373830386139323963666634646633613735626535396330613261636361 +36616234613339373133353165316366643164343264613433656461386465333031386638616166 +37623336326631343762623362666635326231636430626532383338656137353037653032303433 +35386230336633343064623764633332393061316436306433636262376233643638386131333466 +30653233353837303833616431336362666337373138653833666231306530636638323232656464 +33363939336263366239333334643439323939373832353830306661623633656239386338363536 +32373831396431333461663266393062663764363666306464393130306630303431306434616435 +38613762646662656339633436626463636264303932383161623837626264636438363636393136 +35313939303161343033353135373261343731666139303035646165653933383061303430656136 +34363665376161353063363237366130306461376230326231643466636130313436323533666264 +32363538633862343437646366653765376530373739386536336366653766383334323934333438 +63343561333133343336636438353031333535623031613037376236386438336433303234396563 +37326465643137306435353561343662626631616666626130323230306636303562306232373636 +61646163383137663135366563653030353264313437373531326665343935393061366333643731 +33383139623438666532613833396638303763663264373835323835636666303938323563643363 +32646237306139616462303962656363336165623365303638383762353731393235613661383565 +37396437363933376536356534636464353437326134616236653431356566323132333635653136 +30306333646137363633343938373062363764623533633966653762333930393435356635613766 +63393931303133336532363438373766656130316233363139336538353533366537653536613830 +36396435663962393933303564613064353561306362653537616266306566306661306130633730 +61346439663466616264386161323563326239656236613739323562366531313538613265633935 +33303565333063366235666130336537616563303631363331323236326531363138653762356338 +31396564323833356332633536386238383166333562353534306564646462323136633461383330 +63633364643766636266613833643162363132393634376236316233326464646161366630313537 +30333639356363373233646463386138653964326339346233656261373762656332646430316532 +30323336356662326537373030666264663238373039663666363363646430383937323133393235 +64656365396533306230666335343635333736636539313461306433343266633034303531666161 +32333239326662643939366639353563366434303763663061643233343436613739656564323364 +62306337633135623162326564306639363437653338326161643532353634306130643432363864 +34383763656233646136633832393937393033343137353539363235333938316362393436366236 +65316534306337303164373664393036663330383433623335376665653930316364643136303538 +39373337333037373862313165363762353466653733666436613733663035363633653737323036 +62623965356663373365633434663139363930663135613864666331386163656538633934303437 +31303039346439656538343439303137623939626466656430376531653764323137373130366539 +34343564353964623238386439313661613535663762306639656636316637626336383734613538 +65373464333564623762333562636130636133383766653634363736313432373239663661663166 +65333735613837396232303034656531656430333363666633333361303761356632323666313133 +38626134333466646566363139633031616130313530313535373032313362343037643139633531 +31633764346337353061663166353463386462373531333030633435326137336563383034616362 +38313533633563653734346632366162646431626234323161336533666231303764343034633464 +35623738326432316562306539666637636434306263363238616538333532626132386634326334 +63633262636238383462653035393830313963333337623661326335343231313136316331626666 +64613632643832643830316561383665343061643132306333653963653938303961383134306330 +61623834316337356265626630313233376234316466653964333637346136663361666638383130 +61373935313265656638643037386532636666393766663364616239613366343463656331613335 +61343064383532303937313538653566636135376137656534626334336630303534356335363234 +36373165353139383639303363323832393838666137396437333831306637656638623236353433 +37323834613336663064656531363532396564326537316263613239653430666638326435653939 +64303135356236316237633038336565343935316230376431353064383466626634396431643030 +65393737643966626333326563323431333832363133363461636433323931613736313633383137 +65356263363339386666323833346666663163613066303133373566616364656637323937666633 +36343631393166373539663937363765303261326236336530306566346561366434376666663432 +35653432666362393937346434303238363463386530356363353062626265656233636661646533 +61323433303366646530353763343536346132383232356234643466393635663038653765616664 +31373130373637646462373234313162633763313161383639393062326430356232353136653731 +62343734376131323730643266393137326661363938633763303435313334653562613764613230 +64353762616130643131663038336532356366653463363437343562356638363137313165613161 +31303363373965386134363133656161663632356536323366353839356234373937656430663637 +38313532636438333433346235623064623366303130373064316631363764646437316538393963 +65306661333039633034323462346164623737623666663162613734366437303661396236643137 +34356532303834343262653332653963313537663666646332316433643230303166346233313039 +65393763323262656436643865643361633735616365623931653761653363306161323739316434 +62393835326138383433376162363836613636313033353636623834336339333637366137666137 +62363963666265646636616530326138313433656339383433333662386666663362306430343764 +65363163336663363230656233666262663536313031666130323837653930626536623637353530 +30333433393763656635376466346465623961343562333431626362623965643066666362383534 +62393262613939366464343833326435663131366436313634376233373262396132313235396166 +39356564386131363735356536616338653937623333303564626331613238646262656562313664 +32646361656333636230313236643662623730643037333463343531663238313339353631323965 +37313135343130633361306333616663643836386666366238303032393331613930303064643839 +61303737353461346337393039383263643038383137353063323730653532343532313964353464 +64316466363131393662653830383139306339396534616637653536336639303162303766343962 +65333166376133643066643231353466333631656432386162643637666232633431366333353835 +37623734343931623538393961383334353539623439336132633865363364316230643962653632 +38666633303334336639653466316362363263636564633631356533373531326431353930666565 +63346165623463623739373165353231626430346161393239353063663065653565326434643363 +63396537316563636330323065356364396530313036653433303662393838646439333132396462 +38313531356163333032636133333964373436613136333035626439313032653239366437373962 +39363738303265616166623463353363313936616337336639666139663862343161633136366663 +36656230613938333334636665393937636238613236353436336263636163643632313464613836 +65663231353136626161653732363663326364393333666365623361623535633037316637383836 +32636534303932343263653936313966343035623965663133613261353466626434366138333766 +65303062333631313263373333616663373336626636333364363165353666356334643533343738 +32343766376533363838373461363732373139393434346461316630623564613238323636633532 +61323430636136383236326331336161623361313437353463633634353134353565373837653161 +33303638653336623636383431316362376262626361323737623132323933343233306533353536 +36616436643433326139393261613937333231663864333336363335313735376239313164613236 +35306338376565333434323936366439356363383039313362646634323161626662626532393432 +32636231316661336332313633313762623833346338383361353263343563353731346666346633 +30373065626139653335646131336233393437653465396164623531356330346636386465353636 +63323838336537316231336136656638363935346662383863343062306339333036306262383963 +35646166643430646666393166316561366338623264303164626462353862336362613934333533 +66303663353161373764353238343730333635396361343566303939613538306361613438656666 +39376162373336373835383230306261336232613363393638666531363331396332356238313533 +31663065636433353333623763646538303538316231333738396662396338616636336432323966 +31666432653162643736663063333261383034393230616631346662663662346332306562613966 +66653565356566353665366333373134663163623661303262376631633761353437663662326663 +34623535373561633066336162323739393533646138633734313933316264656434663137393130 +36366264663066323635663835643934306536643439326166323461303039633362653537346565 +33633732376235656638323230636437666131636431663932363662376139666532313532363837 +64633338663634666234373636383535346534323039326630383438633263663237653935653563 +33393565383938353939326265386636366532323565353339383032336561353662323161306161 +32313765396463646630616234653738613437326439343935373330316661636561356663613463 +35626537643534383532323931666136393466306239623965356137646231653131323335653032 +61373436313662613634393336366663636431313338636530323061383336313331333132373138 +33643464343837663161643337633837316261636533326662613939626137326161663537353632 +64653264363534333837613432336266353130653861323461363165633765353162306561356238 +64373533633763356434643761623664623164663864393539613432326262393566656262343039 +33666232376464303063623039346233303563356635643233373163326233633161616164323366 +65646532633365363033633163316533383365373733633661386431613261336636323730326662 +61383565316538616237343361373033626233656436646530303535303233623434646333626439 +39353765653666623731656230363062613839376134333034626139643661316266393437323432 +30643964393563323135643332633263306162643632326132373531333931343535353866613265 +32613138653037643664306438623038316535343263393766313166363439386631343031303339 +66303232656234643131306135336335353633616634656539333533343266643333363739303535 +34313362626566363138643565303466303631306431336665633862666137363166653761616335 +30656232393165366362336439383637373064306663366435643665383466396265336231363836 +39383164613630663130383131666334656632663161326261386461336239393037306261613434 +64323839663830313635343866613961333566313364373433393164663137323863356238613237 +63383162323561646334313133386530343163663261373435613064633230653862393066353630 +37343932333332636262376163323961396261313963356333623335613665323232306531363263 +38386532656535613639656462383733303135616562643663663330633063663831393366343962 +65316233636431653835393332383633653534646536623162663039663731633932313136323432 +39653566633965353330306533626236323234316331666462353532653864333034363830373531 +66663135316461393531666465613535336131366234386234663466303438616566626461376636 +35353066663634303930303732383363643761313732363365386137613832623935393961366331 +33393561653139346264366364373831316365366330636339663239303061626333653237373036 +31623762623064313133316363343963373062313435363331333437313037656462323938336566 +30616165353335396536343365313730663430616137626561363835386533353163383930626562 +39666264663537343733323232643661656462396330356334303733306334656366343538653665 +63613637333733663039616566363435663933316531663361626562613638323839353436353766 +35376338633863363937346438356438303031633564353439666265323333336332323631386332 +62303832633863323231646335613562393534656135333430343665336333393332626235326466 +35393037396232353762313134313830663534333661626630613334613064396534626461363038 +33343962343139303761323365333461663061636465323733333536373531613331386539613231 +33663766626238383663373366373934343033646363653431393732303566353461303438633739 +35646261323663626165353866346261663762393862356439623639613534616334393537356362 +61626339333430363965636237646236366134373538363234626632373937376231396333646231 +61616138663337396562663163646531363439666232333563653430393034666161313336663635 +62303866633261656330656264613335346663393236376664333638626161616536336436313339 +36353837613737383562616133356434366134663831386130623464383762353837623638343837 +35643736323330623535326335623330663530356236373230633166383938653538303238366665 +61376264353066643566636430386236383266653531633766613033333261366266666461383137 +30336363363066653662333561333239613231303134636665653533343137336431303037333134 +37313436653333613333366661623832363466333265303465333131366265656265383233303539 +35666234363462373565636239333833313236376330656161336533633038366431666136373934 +66663238313363356662613137333734336663623531623862656335366561303232343262303261 +30323164646439633134383762303065396235613364316534383339333930623561633330626562 +36363036396263653561643139663537626563346339653963396364383463656337386564346434 +63303032303532306432633239643861383333323435666131316664323965623632643032653630 +34386132383131363934613561366135343836666566633162643730643238323336633964366131 +65373264343033666433363037313533373834333363393132343836626335333630613663626536 +63313762306364323333643939393536333639616261303361666334646535636633666333363736 +66626365386533646366633464383139396161336238393761643461363563623035396663333534 +35626335326438353032643437363435633264363336333433386137663531303032623238313362 +65633666323161323064333161626234393639363531623030313738653066333539623866326531 +63386639313464653634653134363231313136373231303331653561336461653230613364333231 +65303230626364323131663930353439376531303239306561353139653738643030643936666264 +61333766326639633766656532363263393838366335643430313865313333333436373061303166 +61333435653834346631646630613130326534323563323537353236376561623935613937386634 +31373436663138643336666263326433326237353837613262646265643436336437653934333638 +37336463306336636335363639636232393863326530326565346261346566373534646262613461 +66383936656236653833336433336639323238623937663030613232666361646565656632343335 +62323237653937633931383936646461373835623961303734666462343563323838613933376538 +64353638383635373535616236623937656561306638633662343163326437346566316534356666 +61383166643136666261613831353136353930616331623665306466393561633161306162636532 +63623761616131356136316365313836393864343234623165616164633861613532646237316136 +62353639396438386532373762363665633065336136623233633266633333346566376666653839 +396237623662663837363564366362346166 diff --git a/compose/roles/infra-common/tasks/main.yml b/compose/roles/infra-common/tasks/main.yml new file mode 100755 index 0000000..fdc43c8 --- /dev/null +++ b/compose/roles/infra-common/tasks/main.yml @@ -0,0 +1,17 @@ +--- +- name: Common for ubuntu + block: + - name: Update repos + become: true + apt: + update_cache: yes + - name: Install packages + become: true + ansible.builtin.apt: + pkg: + - mc +# - name: Set a hostname +# become: true +# ansible.builtin.hostname: +# name: "{{ host_name }}.{{ domain_name }}" +# \ No newline at end of file diff --git a/compose/roles/infra-container-registry/defaults/main.yml b/compose/roles/infra-container-registry/defaults/main.yml new file mode 100644 index 0000000..dfc543d --- /dev/null +++ b/compose/roles/infra-container-registry/defaults/main.yml @@ -0,0 +1,5 @@ +docker_compose_version: "latest" +registry_data_dir: "/opt/registry/data" +host_ssl_cert_dir: "/opt/registry/ssl" +container_ssl_cert_dir: /certs +docker_default_dir: "/opt/docker/registry" diff --git a/compose/roles/infra-container-registry/handlers/main.yml b/compose/roles/infra-container-registry/handlers/main.yml new file mode 100644 index 0000000..730d5b0 --- /dev/null +++ b/compose/roles/infra-container-registry/handlers/main.yml @@ -0,0 +1,2 @@ +- name: Restart registry + command: docker-compose -f /opt/registry/docker-compose.yml restart \ No newline at end of file diff --git a/compose/roles/infra-container-registry/tasks/configure.yml b/compose/roles/infra-container-registry/tasks/configure.yml new file mode 100644 index 0000000..9f66e19 --- /dev/null +++ b/compose/roles/infra-container-registry/tasks/configure.yml @@ -0,0 +1,18 @@ +# tasks/configure.yml +- name: Create necessary directories + file: + path: "{{ item }}" + state: directory + loop: + - "{{ registry_data_dir }}" + - "{{ host_ssl_cert_dir }}" + - "{{ docker_default_dir }}" + +- name: Copy SSL certificates + copy: + src: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}/files/ssl/{{ item }}" + dest: "{{ host_ssl_cert_dir }}/{{ item }}" + loop: + - docker.crt + - docker.key + ignore_errors: yes \ No newline at end of file diff --git a/compose/roles/infra-container-registry/tasks/deploy.yml b/compose/roles/infra-container-registry/tasks/deploy.yml new file mode 100644 index 0000000..04b0f57 --- /dev/null +++ b/compose/roles/infra-container-registry/tasks/deploy.yml @@ -0,0 +1,8 @@ +# tasks/deploy.yml +- name: Copy docker-compose template + template: + src: docker-compose.yml.j2 + dest: /opt/docker/registry/docker-compose.yml + +- name: Start registry using Docker Compose + command: docker-compose -f /opt/docker/registry/docker-compose.yml up -d diff --git a/compose/roles/infra-container-registry/tasks/install.yml b/compose/roles/infra-container-registry/tasks/install.yml new file mode 100644 index 0000000..0813f3c --- /dev/null +++ b/compose/roles/infra-container-registry/tasks/install.yml @@ -0,0 +1,5 @@ +- name: Install required packages + apt: + name: + - docker-compose + state: present diff --git a/compose/roles/infra-container-registry/tasks/main.yml b/compose/roles/infra-container-registry/tasks/main.yml new file mode 100644 index 0000000..0ee31ec --- /dev/null +++ b/compose/roles/infra-container-registry/tasks/main.yml @@ -0,0 +1,9 @@ +# tasks/main.yml +- name: Include install tasks + include_tasks: install.yml + +- name: Include configure tasks + include_tasks: configure.yml + +- name: Include deploy tasks + include_tasks: deploy.yml diff --git a/compose/roles/infra-container-registry/templates/docker-compose.yml.j2 b/compose/roles/infra-container-registry/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..22dca66 --- /dev/null +++ b/compose/roles/infra-container-registry/templates/docker-compose.yml.j2 @@ -0,0 +1,31 @@ +version: '3' +services: + registry: + image: registry:2 + container_name: registry + restart: "always" + ports: + - "443:443" + environment: + REGISTRY_HTTP_ADDR: 0.0.0.0:443 + REGISTRY_HTTP_TLS_CERTIFICATE: {{ container_ssl_cert_dir }}/docker.crt + REGISTRY_HTTP_TLS_KEY: {{ container_ssl_cert_dir }}/docker.key + REGISTRY_STORAGE_DELETE_ENABLED: "true" + volumes: + - {{ registry_data_dir }}:/var/lib/registry + - {{ host_ssl_cert_dir }}:{{ container_ssl_cert_dir}} + ui: + image: joxit/docker-registry-ui:latest + container_name: registry-ui + restart: "always" + ports: + - "8080:8080" + environment: + - REGISTRY_TITLE=Private Docker Registry + - NGINX_PROXY_PASS_URL=https://registry + - NGINX_LISTEN_PORT=8080 + - SINGLE_REGISTRY=true + - DELETE_IMAGES=true + - SHOW_CONTENT_DIGEST=true + depends_on: + - registry \ No newline at end of file diff --git a/elasticsearch/.helmignore b/elasticsearch/.helmignore new file mode 100644 index 0000000..e12c0b4 --- /dev/null +++ b/elasticsearch/.helmignore @@ -0,0 +1,2 @@ +tests/ +.pytest_cache/ diff --git a/elasticsearch/Chart.yaml b/elasticsearch/Chart.yaml new file mode 100644 index 0000000..df17757 --- /dev/null +++ b/elasticsearch/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +appVersion: 8.5.1 +description: Official Elastic helm chart for Elasticsearch +home: https://github.com/elastic/helm-charts +icon: https://helm.elastic.co/icons/elasticsearch.png +maintainers: +- email: helm-charts@elastic.co + name: Elastic +name: elasticsearch +sources: +- https://github.com/elastic/elasticsearch +version: 8.5.1 diff --git a/elasticsearch/Makefile b/elasticsearch/Makefile new file mode 100644 index 0000000..22218a1 --- /dev/null +++ b/elasticsearch/Makefile @@ -0,0 +1 @@ +include ../helpers/common.mk diff --git a/elasticsearch/README.md b/elasticsearch/README.md new file mode 100644 index 0000000..a4948bd --- /dev/null +++ b/elasticsearch/README.md @@ -0,0 +1,490 @@ +# Elasticsearch Helm Chart + +[![Build Status](https://img.shields.io/jenkins/s/https/devops-ci.elastic.co/job/elastic+helm-charts+main.svg)](https://devops-ci.elastic.co/job/elastic+helm-charts+main/) [![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/elastic)](https://artifacthub.io/packages/search?repo=elastic) + +This Helm chart is a lightweight way to configure and run our official +[Elasticsearch Docker image][]. + +> **Warning** +> When it comes to running the Elastic on Kubernetes infrastructure, we +> recommend [Elastic Cloud on Kubernetes][] (ECK) as the best way to run and manage +> the Elastic Stack. +> +> ECK offers many operational benefits for both our basic-tier and our +> enterprise-tier customers, such as spinning up cluster nodes that were lost on +> failed infrastructure, seamless upgrades, rolling cluster changes, and much +> much more. +> +> With the release of the Elastic Stack Helm charts for Elastic version 8.5.1, +> we are handing over the ongoing maintenance of our Elastic Stack Helm charts +> to the community and contributors. This repository will finally be archived +> after 6 months time. Elastic Stacks deployed on Kubernetes through Helm charts +> will still be fully supported under EOL limitations. +> +> Since we want to provide an even better experience for our customers by +> running the Elastic Stack on Kubernetes, we will continue maintaining the +> Helm charts applicable to ECK Custom Resources. These charts can be found in +> the [ECK repository][eck-charts]. +> +> Helm charts will currently be maintained for ECK Enterprise-tier customers, +> however, we encourage the community to engage with the existing Helm charts +> for the Elastic Stack and continue supporting their ongoing maintenance. +> +> See for more details. + + + + + +- [Requirements](#requirements) +- [Installing](#installing) + - [Install a released version using the Helm repository](#install-a-released-version-using-the-helm-repository) + - [Install a development version using the main branch](#install-a-development-version-using-the-main-branch) +- [Upgrading](#upgrading) +- [Usage notes](#usage-notes) +- [Configuration](#configuration) +- [FAQ](#faq) + - [How to deploy this chart on a specific K8S distribution?](#how-to-deploy-this-chart-on-a-specific-k8s-distribution) + - [How to deploy dedicated nodes types?](#how-to-deploy-dedicated-nodes-types) + - [Coordinating nodes](#coordinating-nodes) + - [Clustering and Node Discovery](#clustering-and-node-discovery) + - [How to deploy clusters with security (authentication and TLS) enabled?](#how-to-deploy-clusters-with-security-authentication-and-tls-enabled) + - [How to migrate from helm/charts stable chart?](#how-to-migrate-from-helmcharts-stable-chart) + - [How to install plugins?](#how-to-install-plugins) + - [How to use the keystore?](#how-to-use-the-keystore) + - [Basic example](#basic-example) + - [Multiple keys](#multiple-keys) + - [Custom paths and keys](#custom-paths-and-keys) + - [How to enable snapshotting?](#how-to-enable-snapshotting) + - [How to configure templates post-deployment?](#how-to-configure-templates-post-deployment) +- [Contributing](#contributing) + + + + + + +## Requirements + +* Minimum cluster requirements include the following to run this chart with +default settings. All of these settings are configurable. + * Three Kubernetes nodes to respect the default "hard" affinity settings + * 1GB of RAM for the JVM heap + +See [supported configurations][] for more details. + + +## Installing + +### Install a released version using the Helm repository + +* Add the Elastic Helm charts repo: +`helm repo add elastic https://helm.elastic.co` + +* Install it: `helm install elasticsearch elastic/elasticsearch` + +### Install a development version using the main branch + +* Clone the git repo: `git clone git@github.com:elastic/helm-charts.git` + +* Install it: `helm install elasticsearch ./helm-charts/elasticsearch --set imageTag=8.5.1` + +## Upgrading + +Please always check [CHANGELOG.md][] and [BREAKING_CHANGES.md][] before +upgrading to a new chart version. + + +## Usage notes + +* This repo includes several [examples][] of configurations that can be used +as a reference. They are also used in the automated testing of this chart. +* Automated testing of this chart is currently only run against GKE (Google +Kubernetes Engine). +* The chart deploys a StatefulSet and by default will do an automated rolling +update of your cluster. It does this by waiting for the cluster health to become +green after each instance is updated. If you prefer to update manually you can +set `OnDelete` [updateStrategy][]. +* It is important to verify that the JVM heap size in `esJavaOpts` and to set +the CPU/Memory `resources` to something suitable for your cluster. +* To simplify chart and maintenance each set of node groups is deployed as a +separate Helm release. Take a look at the [multi][] example to get an idea for +how this works. Without doing this it isn't possible to resize persistent +volumes in a StatefulSet. By setting it up this way it makes it possible to add +more nodes with a new storage size then drain the old ones. It also solves the +problem of allowing the user to determine which node groups to update first when +doing upgrades or changes. +* We have designed this chart to be very un-opinionated about how to configure +Elasticsearch. It exposes ways to set environment variables and mount secrets +inside of the container. Doing this makes it much easier for this chart to +support multiple versions with minimal changes. + + +## Configuration + +| Parameter | Description | Default | +|------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------| +| `antiAffinityTopologyKey` | The [anti-affinity][] topology key. By default this will prevent multiple Elasticsearch nodes from running on the same Kubernetes node | `kubernetes.io/hostname` | +| `antiAffinity` | Setting this to hard enforces the [anti-affinity][] rules. If it is set to soft it will be done "best effort". Other values will be ignored | `hard` | +| `clusterHealthCheckParams` | The [Elasticsearch cluster health status params][] that will be used by readiness [probe][] command | `wait_for_status=green&timeout=1s` | +| `clusterName` | This will be used as the Elasticsearch [cluster.name][] and should be unique per cluster in the namespace | `elasticsearch` | +| `createCert` | This will automatically create the SSL certificates | `true` | +| `enableServiceLinks` | Set to false to disabling service links, which can cause slow pod startup times when there are many services in the current namespace. | `true` | +| `envFrom` | Templatable string to be passed to the [environment from variables][] which will be appended to the `envFrom:` definition for the container | `[]` | +| `esConfig` | Allows you to add any config files in `/usr/share/elasticsearch/config/` such as `elasticsearch.yml` and `log4j2.properties`. See [values.yaml][] for an example of the formatting | `{}` | +| `esJavaOpts` | [Java options][] for Elasticsearch. This is where you could configure the [jvm heap size][] | `""` | +| `esJvmOptions` | [Java options][] for Elasticsearch. Override the default JVM options by adding custom options files . See [values.yaml][] for an example of the formatting | `{}` | +| `esMajorVersion` | Deprecated. Instead, use the version of the chart corresponding to your ES minor version. Used to set major version specific configuration. If you are using a custom image and not running the default Elasticsearch version you will need to set this to the version you are running (e.g. `esMajorVersion: 6`) | `""` | +| `extraContainers` | Templatable string of additional `containers` to be passed to the `tpl` function | `""` | +| `extraEnvs` | Extra [environment variables][] which will be appended to the `env:` definition for the container | `[]` | +| `extraInitContainers` | Templatable string of additional `initContainers` to be passed to the `tpl` function | `""` | +| `extraVolumeMounts` | Templatable string of additional `volumeMounts` to be passed to the `tpl` function | `""` | +| `extraVolumes` | Templatable string of additional `volumes` to be passed to the `tpl` function | `""` | +| `fullnameOverride` | Overrides the `clusterName` and `nodeGroup` when used in the naming of resources. This should only be used when using a single `nodeGroup`, otherwise you will have name conflicts | `""` | +| `healthNameOverride` | Overrides `test-elasticsearch-health` pod name | `""` | +| `hostAliases` | Configurable [hostAliases][] | `[]` | +| `httpPort` | The http port that Kubernetes will use for the healthchecks and the service. If you change this you will also need to set [http.port][] in `extraEnvs` | `9200` | +| `imagePullPolicy` | The Kubernetes [imagePullPolicy][] value | `IfNotPresent` | +| `imagePullSecrets` | Configuration for [imagePullSecrets][] so that you can use a private registry for your image | `[]` | +| `imageTag` | The Elasticsearch Docker image tag | `8.5.1` | +| `image` | The Elasticsearch Docker image | `docker.elastic.co/elasticsearch/elasticsearch` | +| `ingress` | Configurable [ingress][] to expose the Elasticsearch service. See [values.yaml][] for an example | see [values.yaml][] | +| `initResources` | Allows you to set the [resources][] for the `initContainer` in the StatefulSet | `{}` | +| `keystore` | Allows you map Kubernetes secrets into the keystore. See the [config example][] and [how to use the keystore][] | `[]` | +| `labels` | Configurable [labels][] applied to all Elasticsearch pods | `{}` | +| `lifecycle` | Allows you to add [lifecycle hooks][]. See [values.yaml][] for an example of the formatting | `{}` | +| `masterService` | The service name used to connect to the masters. You only need to set this if your master `nodeGroup` is set to something other than `master`. See [Clustering and Node Discovery][] for more information | `""` | +| `maxUnavailable` | The [maxUnavailable][] value for the pod disruption budget. By default this will prevent Kubernetes from having more than 1 unhealthy pod in the node group | `1` | +| `minimumMasterNodes` | The value for [discovery.zen.minimum_master_nodes][]. Should be set to `(master_eligible_nodes / 2) + 1`. Ignored in Elasticsearch versions >= 7 | `2` | +| `nameOverride` | Overrides the `clusterName` when used in the naming of resources | `""` | +| `networkHost` | Value for the [network.host Elasticsearch setting][] | `0.0.0.0` | +| `networkPolicy` | The [NetworkPolicy](https://kubernetes.io/docs/concepts/services-networking/network-policies/) to set. See [`values.yaml`](./values.yaml) for an example | `{http.enabled: false,transport.enabled: false}` | +| `nodeAffinity` | Value for the [node affinity settings][] | `{}` | +| `nodeGroup` | This is the name that will be used for each group of nodes in the cluster. The name will be `clusterName-nodeGroup-X` , `nameOverride-nodeGroup-X` if a `nameOverride` is specified, and `fullnameOverride-X` if a `fullnameOverride` is specified | `master` | +| `nodeSelector` | Configurable [nodeSelector][] so that you can target specific nodes for your Elasticsearch cluster | `{}` | +| `persistence` | Enables a persistent volume for Elasticsearch data. Can be disabled for nodes that only have [roles][] which don't require persistent data | see [values.yaml][] | +| `podAnnotations` | Configurable [annotations][] applied to all Elasticsearch pods | `{}` | +| `podManagementPolicy` | By default Kubernetes [deploys StatefulSets serially][]. This deploys them in parallel so that they can discover each other | `Parallel` | +| `podSecurityContext` | Allows you to set the [securityContext][] for the pod | see [values.yaml][] | +| `podSecurityPolicy` | Configuration for create a pod security policy with minimal permissions to run this Helm chart with `create: true`. Also can be used to reference an external pod security policy with `name: "externalPodSecurityPolicy"` | see [values.yaml][] | +| `priorityClassName` | The name of the [PriorityClass][]. No default is supplied as the PriorityClass must be created first | `""` | +| `protocol` | The protocol that will be used for the readiness [probe][]. Change this to `https` if you have `xpack.security.http.ssl.enabled` set | `http` | +| `rbac` | Configuration for creating a role, role binding and ServiceAccount as part of this Helm chart with `create: true`. Also can be used to reference an external ServiceAccount with `serviceAccountName: "externalServiceAccountName"`, or automount the service account token | see [values.yaml][] | +| `readinessProbe` | Configuration fields for the readiness [probe][] | see [values.yaml][] | +| `replicas` | Kubernetes replica count for the StatefulSet (i.e. how many pods) | `3` | +| `resources` | Allows you to set the [resources][] for the StatefulSet | see [values.yaml][] | +| `roles` | A list with the specific [roles][] for the `nodeGroup` | see [values.yaml][] | +| `schedulerName` | Name of the [alternate scheduler][] | `""` | +| `secret.enabled` | Enable Secret creation for Elasticsearch credentials | `true` | +| `secret.password` | Initial password for the elastic user | `""` (generated randomly) | +| `secretMounts` | Allows you easily mount a secret as a file inside the StatefulSet. Useful for mounting certificates and other secrets. See [values.yaml][] for an example | `[]` | +| `securityContext` | Allows you to set the [securityContext][] for the container | see [values.yaml][] | +| `service.annotations` | [LoadBalancer annotations][] that Kubernetes will use for the service. This will configure load balancer if `service.type` is `LoadBalancer` | `{}` | +| `service.enabled` | Enable non-headless service | `true` | +| `service.externalTrafficPolicy` | Some cloud providers allow you to specify the [LoadBalancer externalTrafficPolicy][]. Kubernetes will use this to preserve the client source IP. This will configure load balancer if `service.type` is `LoadBalancer` | `""` | +| `service.httpPortName` | The name of the http port within the service | `http` | +| `service.labelsHeadless` | Labels to be added to headless service | `{}` | +| `service.labels` | Labels to be added to non-headless service | `{}` | +| `service.loadBalancerIP` | Some cloud providers allow you to specify the [loadBalancer][] IP. If the `loadBalancerIP` field is not specified, the IP is dynamically assigned. If you specify a `loadBalancerIP` but your cloud provider does not support the feature, it is ignored. | `""` | +| `service.loadBalancerSourceRanges` | The IP ranges that are allowed to access | `[]` | +| `service.nodePort` | Custom [nodePort][] port that can be set if you are using `service.type: nodePort` | `""` | +| `service.transportPortName` | The name of the transport port within the service | `transport` | +| `service.publishNotReadyAddresses` | Consider that all endpoints are considered "ready" even if the Pods themselves are not | `false` | +| `service.type` | Elasticsearch [Service Types][] | `ClusterIP` | +| `sysctlInitContainer` | Allows you to disable the `sysctlInitContainer` if you are setting [sysctl vm.max_map_count][] with another method | `enabled: true` | +| `sysctlVmMaxMapCount` | Sets the [sysctl vm.max_map_count][] needed for Elasticsearch | `262144` | +| `terminationGracePeriod` | The [terminationGracePeriod][] in seconds used when trying to stop the pod | `120` | +| `tests.enabled` | Enable creating test related resources when running `helm template` or `helm test` | `true` | +| `tolerations` | Configurable [tolerations][] | `[]` | +| `transportPort` | The transport port that Kubernetes will use for the service. If you change this you will also need to set [transport port configuration][] in `extraEnvs` | `9300` | +| `updateStrategy` | The [updateStrategy][] for the StatefulSet. By default Kubernetes will wait for the cluster to be green after upgrading each pod. Setting this to `OnDelete` will allow you to manually delete each pod during upgrades | `RollingUpdate` | +| `volumeClaimTemplate` | Configuration for the [volumeClaimTemplate for StatefulSets][]. You will want to adjust the storage (default `30Gi` ) and the `storageClassName` if you are using a different storage class | see [values.yaml][] | + + +## FAQ + +### How to deploy this chart on a specific K8S distribution? + +This chart is designed to run on production scale Kubernetes clusters with +multiple nodes, lots of memory and persistent storage. For that reason it can be +a bit tricky to run them against local Kubernetes environments such as +[Minikube][]. + +This chart is highly tested with [GKE][], but some K8S distribution also +requires specific configurations. + +We provide examples of configuration for the following K8S providers: + +- [Docker for Mac][] +- [KIND][] +- [Minikube][] +- [MicroK8S][] +- [OpenShift][] + +### How to deploy dedicated nodes types? + +All the Elasticsearch pods deployed share the same configuration. If you need to +deploy dedicated [nodes types][] (for example dedicated master and data nodes), +you can deploy multiple releases of this chart with different configurations +while they share the same `clusterName` value. + +For each Helm release, the nodes types can then be defined using `roles` value. + +An example of Elasticsearch cluster using 2 different Helm releases for master, +data and coordinating nodes can be found in [examples/multi][]. + +#### Coordinating nodes + +Every node is implicitly a coordinating node. This means that a node that has an +explicit empty list of roles will only act as a coordinating node. + +When deploying coordinating-only node with Elasticsearch chart, it is required +to define the empty list of roles in both `roles` value and `node.roles` +settings: + +```yaml +roles: [] + +esConfig: + elasticsearch.yml: | + node.roles: [] +``` + +More details in [#1186 (comment)][] + +#### Clustering and Node Discovery + +This chart facilitates Elasticsearch node discovery and services by creating two +`Service` definitions in Kubernetes, one with the name `$clusterName-$nodeGroup` +and another named `$clusterName-$nodeGroup-headless`. +Only `Ready` pods are a part of the `$clusterName-$nodeGroup` service, while all +pods ( `Ready` or not) are a part of `$clusterName-$nodeGroup-headless`. + +If your group of master nodes has the default `nodeGroup: master` then you can +just add new groups of nodes with a different `nodeGroup` and they will +automatically discover the correct master. If your master nodes have a different +`nodeGroup` name then you will need to set `masterService` to +`$clusterName-$masterNodeGroup`. + +The chart value for `masterService` is used to populate +`discovery.zen.ping.unicast.hosts` , which Elasticsearch nodes will use to +contact master nodes and form a cluster. +Therefore, to add a group of nodes to an existing cluster, setting +`masterService` to the desired `Service` name of the related cluster is +sufficient. + +### How to deploy clusters with security (authentication and TLS) enabled? + +This Helm chart can generate a [Kubernetes Secret][] or use an existing one to +setup Elastic credentials. + +This Helm chart can use existing [Kubernetes Secret][] to setup Elastic +certificates for example. These secrets should be created outside of this chart +and accessed using [environment variables][] and volumes. + +This chart is setting TLS and creating a certificate by default, but you can also provide your own certs as a K8S secret. An example of configuration for providing existing certificates can be found in [examples/security][]. + +### How to migrate from helm/charts stable chart? + +If you currently have a cluster deployed with the [helm/charts stable][] chart +you can follow the [migration guide][]. + +### How to install plugins? + +The recommended way to install plugins into our Docker images is to create a +[custom Docker image][]. + +The Dockerfile would look something like: + +``` +ARG elasticsearch_version +FROM docker.elastic.co/elasticsearch/elasticsearch:${elasticsearch_version} + +RUN bin/elasticsearch-plugin install --batch repository-gcs +``` + +And then updating the `image` in values to point to your custom image. + +There are a couple reasons we recommend this. + +1. Tying the availability of Elasticsearch to the download service to install +plugins is not a great idea or something that we recommend. Especially in +Kubernetes where it is normal and expected for a container to be moved to +another host at random times. +2. Mutating the state of a running Docker image (by installing plugins) goes +against best practices of containers and immutable infrastructure. + +### How to use the keystore? + +#### Basic example + +Create the secret, the key name needs to be the keystore key path. In this +example we will create a secret from a file and from a literal string. + +``` +kubectl create secret generic encryption-key --from-file=xpack.watcher.encryption_key=./watcher_encryption_key +kubectl create secret generic slack-hook --from-literal=xpack.notification.slack.account.monitoring.secure_url='https://hooks.slack.com/services/asdasdasd/asdasdas/asdasd' +``` + +To add these secrets to the keystore: + +``` +keystore: + - secretName: encryption-key + - secretName: slack-hook +``` + +#### Multiple keys + +All keys in the secret will be added to the keystore. To create the previous +example in one secret you could also do: + +``` +kubectl create secret generic keystore-secrets --from-file=xpack.watcher.encryption_key=./watcher_encryption_key --from-literal=xpack.notification.slack.account.monitoring.secure_url='https://hooks.slack.com/services/asdasdasd/asdasdas/asdasd' +``` + +``` +keystore: + - secretName: keystore-secrets +``` + +#### Custom paths and keys + +If you are using these secrets for other applications (besides the Elasticsearch +keystore) then it is also possible to specify the keystore path and which keys +you want to add. Everything specified under each `keystore` item will be passed +through to the `volumeMounts` section for mounting the [secret][]. In this +example we will only add the `slack_hook` key from a secret that also has other +keys. Our secret looks like this: + +``` +kubectl create secret generic slack-secrets --from-literal=slack_channel='#general' --from-literal=slack_hook='https://hooks.slack.com/services/asdasdasd/asdasdas/asdasd' +``` + +We only want to add the `slack_hook` key to the keystore at path +`xpack.notification.slack.account.monitoring.secure_url`: + +``` +keystore: + - secretName: slack-secrets + items: + - key: slack_hook + path: xpack.notification.slack.account.monitoring.secure_url +``` + +You can also take a look at the [config example][] which is used as part of the +automated testing pipeline. + +### How to enable snapshotting? + +1. Install your [snapshot plugin][] into a custom Docker image following the +[how to install plugins guide][]. +2. Add any required secrets or credentials into an Elasticsearch keystore +following the [how to use the keystore][] guide. +3. Configure the [snapshot repository][] as you normally would. +4. To automate snapshots you can use [Snapshot Lifecycle Management][] or a tool +like [curator][]. + +### How to configure templates post-deployment? + +You can use `postStart` [lifecycle hooks][] to run code triggered after a +container is created. + +Here is an example of `postStart` hook to configure templates: + +```yaml +lifecycle: + postStart: + exec: + command: + - bash + - -c + - | + #!/bin/bash + # Add a template to adjust number of shards/replicas + TEMPLATE_NAME=my_template + INDEX_PATTERN="logstash-*" + SHARD_COUNT=8 + REPLICA_COUNT=1 + ES_URL=http://localhost:9200 + while [[ "$(curl -s -o /dev/null -w '%{http_code}\n' $ES_URL)" != "200" ]]; do sleep 1; done + curl -XPUT "$ES_URL/_template/$TEMPLATE_NAME" -H 'Content-Type: application/json' -d'{"index_patterns":['\""$INDEX_PATTERN"\"'],"settings":{"number_of_shards":'$SHARD_COUNT',"number_of_replicas":'$REPLICA_COUNT'}}' +``` + + +## Contributing + +Please check [CONTRIBUTING.md][] before any contribution or for any questions +about our development and testing process. + +[#1186 (comment)]: https://github.com/elastic/helm-charts/pull/1186#discussion_r631166442 +[alternate scheduler]: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/#specify-schedulers-for-pods +[annotations]: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ +[anti-affinity]: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity +[BREAKING_CHANGES.md]: https://github.com/elastic/helm-charts/blob/main/BREAKING_CHANGES.md +[CHANGELOG.md]: https://github.com/elastic/helm-charts/blob/main/CHANGELOG.md +[cluster.name]: https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster.name.html +[clustering and node discovery]: https://github.com/elastic/helm-charts/blob/main/elasticsearch/README.md#clustering-and-node-discovery +[config example]: https://github.com/elastic/helm-charts/blob/main/elasticsearch/examples/config/values.yaml +[CONTRIBUTING.md]: https://github.com/elastic/helm-charts/blob/main/CONTRIBUTING.md +[curator]: https://www.elastic.co/guide/en/elasticsearch/client/curator/current/snapshot.html +[custom docker image]: https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#_c_customized_image +[deploys statefulsets serially]: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies +[discovery.zen.minimum_master_nodes]: https://www.elastic.co/guide/en/elasticsearch/reference/current/discovery-settings.html#minimum_master_nodes +[docker for mac]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/docker-for-mac +[eck-charts]: https://github.com/elastic/cloud-on-k8s/tree/master/deploy +[elastic cloud on kubernetes]: https://github.com/elastic/cloud-on-k8s +[elasticsearch cluster health status params]: https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-health.html#request-params +[elasticsearch docker image]: https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html +[environment from variables]: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#configure-all-key-value-pairs-in-a-configmap-as-container-environment-variables +[environment variables]: https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/#using-environment-variables-inside-of-your-config +[examples]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/ +[examples/multi]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/multi +[examples/security]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/security +[gke]: https://cloud.google.com/kubernetes-engine +[helm]: https://helm.sh +[helm/charts stable]: https://github.com/helm/charts/tree/master/stable/elasticsearch/ +[hostAliases]: https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ +[how to install plugins guide]: https://github.com/elastic/helm-charts/blob/main/elasticsearch/README.md#how-to-install-plugins +[how to use the keystore]: https://github.com/elastic/helm-charts/blob/main/elasticsearch/README.md#how-to-use-the-keystore +[http.port]: https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-http.html#_settings +[imagePullPolicy]: https://kubernetes.io/docs/concepts/containers/images/#updating-images +[imagePullSecrets]: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/#create-a-pod-that-uses-your-secret +[ingress]: https://kubernetes.io/docs/concepts/services-networking/ingress/ +[java options]: https://www.elastic.co/guide/en/elasticsearch/reference/current/jvm-options.html +[jvm heap size]: https://www.elastic.co/guide/en/elasticsearch/reference/current/heap-size.html +[kind]: https://github.com/elastic/helm-charts/tree/main//elasticsearch/examples/kubernetes-kind +[labels]: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ +[lifecycle hooks]: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/ +[loadBalancer annotations]: https://kubernetes.io/docs/concepts/services-networking/service/#ssl-support-on-aws +[loadBalancer externalTrafficPolicy]: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip +[loadBalancer]: https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer +[maxUnavailable]: https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget +[microk8s]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/microk8s +[migration guide]: https://github.com/elastic/helm-charts/blob/main/elasticsearch/examples/migration/README.md +[minikube]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/minikube +[multi]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/multi/ +[network.host elasticsearch setting]: https://www.elastic.co/guide/en/elasticsearch/reference/current/network.host.html +[node affinity settings]: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#node-affinity-beta-feature +[nodePort]: https://kubernetes.io/docs/concepts/services-networking/service/#nodeport +[nodes types]: https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html +[nodeSelector]: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector +[openshift]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/openshift +[priorityClass]: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass +[probe]: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/ +[resources]: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ +[roles]: https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html +[secret]: https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets +[securityContext]: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +[service types]: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types +[snapshot lifecycle management]: https://www.elastic.co/guide/en/elasticsearch/reference/current/snapshot-lifecycle-management.html +[snapshot plugin]: https://www.elastic.co/guide/en/elasticsearch/plugins/current/repository.html +[snapshot repository]: https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-snapshots.html +[supported configurations]: https://github.com/elastic/helm-charts/blob/main/README.md#supported-configurations +[sysctl vm.max_map_count]: https://www.elastic.co/guide/en/elasticsearch/reference/current/vm-max-map-count.html#vm-max-map-count +[terminationGracePeriod]: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods +[tolerations]: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ +[transport port configuration]: https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-transport.html#_transport_settings +[updateStrategy]: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/ +[values.yaml]: https://github.com/elastic/helm-charts/blob/main/elasticsearch/values.yaml +[volumeClaimTemplate for statefulsets]: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-storage diff --git a/elasticsearch/examples/config/Makefile b/elasticsearch/examples/config/Makefile new file mode 100644 index 0000000..9ae9c37 --- /dev/null +++ b/elasticsearch/examples/config/Makefile @@ -0,0 +1,21 @@ +default: test + +include ../../../helpers/examples.mk + +RELEASE := helm-es-config +TIMEOUT := 1200s + +install: + helm upgrade --wait --timeout=$(TIMEOUT) --install --values values.yaml $(RELEASE) ../../ + +secrets: + kubectl delete secret elastic-config-credentials elastic-config-secret elastic-config-slack elastic-config-custom-path || true + kubectl create secret generic elastic-config-credentials --from-literal=password=changeme --from-literal=username=elastic + kubectl create secret generic elastic-config-slack --from-literal=xpack.notification.slack.account.monitoring.secure_url='https://hooks.slack.com/services/asdasdasd/asdasdas/asdasd' + kubectl create secret generic elastic-config-secret --from-file=xpack.watcher.encryption_key=./watcher_encryption_key + kubectl create secret generic elastic-config-custom-path --from-literal=slack_url='https://hooks.slack.com/services/asdasdasd/asdasdas/asdasd' --from-literal=thing_i_don_tcare_about=test + +test: secrets install goss + +purge: + helm del $(RELEASE) diff --git a/elasticsearch/examples/config/README.md b/elasticsearch/examples/config/README.md new file mode 100644 index 0000000..76dd045 --- /dev/null +++ b/elasticsearch/examples/config/README.md @@ -0,0 +1,27 @@ +# Config + +This example deploy a single node Elasticsearch 8.5.1 with authentication and +custom [values][]. + + +## Usage + +* Create the required secrets: `make secrets` + +* Deploy Elasticsearch chart with the default values: `make install` + +* You can now setup a port forward to query Elasticsearch API: + + ``` + kubectl port-forward svc/config-master 9200 + curl -u elastic:changeme http://localhost:9200/_cat/indices + ``` + + +## Testing + +You can also run [goss integration tests][] using `make test` + + +[goss integration tests]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/config/test/goss.yaml +[values]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/config/values.yaml diff --git a/elasticsearch/examples/config/test/goss.yaml b/elasticsearch/examples/config/test/goss.yaml new file mode 100644 index 0000000..b71ee37 --- /dev/null +++ b/elasticsearch/examples/config/test/goss.yaml @@ -0,0 +1,31 @@ +http: + https://localhost:9200/_cluster/health: + status: 200 + timeout: 2000 + allow-insecure: true + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + body: + - "green" + - '"number_of_nodes":1' + - '"number_of_data_nodes":1' + + https://localhost:9200: + status: 200 + timeout: 2000 + username: elastic + allow-insecure: true + password: "{{ .Env.ELASTIC_PASSWORD }}" + body: + - '"cluster_name" : "config"' + - "You Know, for Search" + +command: + "elasticsearch-keystore list": + exit-status: 0 + stdout: + - keystore.seed + - bootstrap.password + - xpack.notification.slack.account.monitoring.secure_url + - xpack.notification.slack.account.otheraccount.secure_url + - xpack.watcher.encryption_key diff --git a/elasticsearch/examples/config/values.yaml b/elasticsearch/examples/config/values.yaml new file mode 100644 index 0000000..d90e0c8 --- /dev/null +++ b/elasticsearch/examples/config/values.yaml @@ -0,0 +1,29 @@ +--- +clusterName: "config" +replicas: 1 + +extraEnvs: + - name: ELASTIC_PASSWORD + valueFrom: + secretKeyRef: + name: elastic-config-credentials + key: password + +# This is just a dummy file to make sure that +# the keystore can be mounted at the same time +# as a custom elasticsearch.yml +esConfig: + elasticsearch.yml: | + xpack.security.enabled: true + path.data: /usr/share/elasticsearch/data + +keystore: + - secretName: elastic-config-secret + - secretName: elastic-config-slack + - secretName: elastic-config-custom-path + items: + - key: slack_url + path: xpack.notification.slack.account.otheraccount.secure_url + +secret: + enabled: false diff --git a/elasticsearch/examples/config/watcher_encryption_key b/elasticsearch/examples/config/watcher_encryption_key new file mode 100644 index 0000000..b5f9078 --- /dev/null +++ b/elasticsearch/examples/config/watcher_encryption_key @@ -0,0 +1 @@ +supersecret diff --git a/elasticsearch/examples/default/Makefile b/elasticsearch/examples/default/Makefile new file mode 100644 index 0000000..389bf99 --- /dev/null +++ b/elasticsearch/examples/default/Makefile @@ -0,0 +1,14 @@ +default: test + +include ../../../helpers/examples.mk + +RELEASE := helm-es-default +TIMEOUT := 1200s + +install: + helm upgrade --wait --timeout=$(TIMEOUT) --install $(RELEASE) ../../ + +test: install goss + +purge: + helm del $(RELEASE) diff --git a/elasticsearch/examples/default/README.md b/elasticsearch/examples/default/README.md new file mode 100644 index 0000000..6a82ee2 --- /dev/null +++ b/elasticsearch/examples/default/README.md @@ -0,0 +1,25 @@ +# Default + +This example deploy a 3 nodes Elasticsearch 8.5.1 cluster using +[default values][]. + + +## Usage + +* Deploy Elasticsearch chart with the default values: `make install` + +* You can now setup a port forward to query Elasticsearch API: + + ``` + kubectl port-forward svc/elasticsearch-master 9200 + curl localhost:9200/_cat/indices + ``` + + +## Testing + +You can also run [goss integration tests][] using `make test` + + +[goss integration tests]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/default/test/goss.yaml +[default values]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/values.yaml diff --git a/elasticsearch/examples/default/rolling_upgrade.sh b/elasticsearch/examples/default/rolling_upgrade.sh new file mode 100644 index 0000000..c5a2a88 --- /dev/null +++ b/elasticsearch/examples/default/rolling_upgrade.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash -x + +kubectl proxy || true & + +make & +PROC_ID=$! + +while kill -0 "$PROC_ID" >/dev/null 2>&1; do + echo "PROCESS IS RUNNING" + if curl --fail 'http://localhost:8001/api/v1/proxy/namespaces/default/services/elasticsearch-master:9200/_search' ; then + echo "cluster is healthy" + else + echo "cluster not healthy!" + exit 1 + fi + sleep 1 +done +echo "PROCESS TERMINATED" +exit 0 diff --git a/elasticsearch/examples/default/test/goss.yaml b/elasticsearch/examples/default/test/goss.yaml new file mode 100644 index 0000000..925203b --- /dev/null +++ b/elasticsearch/examples/default/test/goss.yaml @@ -0,0 +1,44 @@ +kernel-param: + vm.max_map_count: + value: "262144" + +http: + https://elasticsearch-master:9200/_cluster/health: + status: 200 + timeout: 2000 + username: elastic + allow-insecure: true + password: "{{ .Env.ELASTIC_PASSWORD }}" + body: + - "green" + - '"number_of_nodes":3' + - '"number_of_data_nodes":3' + + https://localhost:9200: + status: 200 + timeout: 2000 + allow-insecure: true + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + body: + - '"number" : "8.5.1"' + - '"cluster_name" : "elasticsearch"' + - "You Know, for Search" + +file: + /usr/share/elasticsearch/data: + exists: true + mode: "2775" + owner: root + group: elasticsearch + filetype: directory + +mount: + /usr/share/elasticsearch/data: + exists: true + +user: + elasticsearch: + exists: true + uid: 1000 + gid: 1000 diff --git a/elasticsearch/examples/docker-for-mac/Makefile b/elasticsearch/examples/docker-for-mac/Makefile new file mode 100644 index 0000000..18fd053 --- /dev/null +++ b/elasticsearch/examples/docker-for-mac/Makefile @@ -0,0 +1,13 @@ +default: test + +RELEASE := helm-es-docker-for-mac +TIMEOUT := 1200s + +install: + helm upgrade --wait --timeout=$(TIMEOUT) --install --values values.yaml $(RELEASE) ../../ + +test: install + helm test $(RELEASE) + +purge: + helm del $(RELEASE) diff --git a/elasticsearch/examples/docker-for-mac/README.md b/elasticsearch/examples/docker-for-mac/README.md new file mode 100644 index 0000000..3fec05d --- /dev/null +++ b/elasticsearch/examples/docker-for-mac/README.md @@ -0,0 +1,23 @@ +# Docker for Mac + +This example deploy a 3 nodes Elasticsearch 8.5.1 cluster on [Docker for Mac][] +using [custom values][]. + +Note that this configuration should be used for test only and isn't recommended +for production. + + +## Usage + +* Deploy Elasticsearch chart with the default values: `make install` + +* You can now setup a port forward to query Elasticsearch API: + + ``` + kubectl port-forward svc/elasticsearch-master 9200 + curl localhost:9200/_cat/indices + ``` + + +[custom values]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/docker-for-mac/values.yaml +[docker for mac]: https://docs.docker.com/docker-for-mac/kubernetes/ diff --git a/elasticsearch/examples/docker-for-mac/values.yaml b/elasticsearch/examples/docker-for-mac/values.yaml new file mode 100644 index 0000000..f7deba6 --- /dev/null +++ b/elasticsearch/examples/docker-for-mac/values.yaml @@ -0,0 +1,23 @@ +--- +# Permit co-located instances for solitary minikube virtual machines. +antiAffinity: "soft" + +# Shrink default JVM heap. +esJavaOpts: "-Xmx128m -Xms128m" + +# Allocate smaller chunks of memory per pod. +resources: + requests: + cpu: "100m" + memory: "512M" + limits: + cpu: "1000m" + memory: "512M" + +# Request smaller persistent volumes. +volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "hostpath" + resources: + requests: + storage: 100M diff --git a/elasticsearch/examples/kubernetes-kind/Makefile b/elasticsearch/examples/kubernetes-kind/Makefile new file mode 100644 index 0000000..9e5602d --- /dev/null +++ b/elasticsearch/examples/kubernetes-kind/Makefile @@ -0,0 +1,17 @@ +default: test + +RELEASE := helm-es-kind +TIMEOUT := 1200s + +install: + helm upgrade --wait --timeout=$(TIMEOUT) --install --values values.yaml $(RELEASE) ../../ + +install-local-path: + kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml + helm upgrade --wait --timeout=$(TIMEOUT) --install --values values-local-path.yaml $(RELEASE) ../../ + +test: install + helm test $(RELEASE) + +purge: + helm del $(RELEASE) diff --git a/elasticsearch/examples/kubernetes-kind/README.md b/elasticsearch/examples/kubernetes-kind/README.md new file mode 100644 index 0000000..431cde3 --- /dev/null +++ b/elasticsearch/examples/kubernetes-kind/README.md @@ -0,0 +1,36 @@ +# KIND + +This example deploy a 3 nodes Elasticsearch 8.5.1 cluster on [Kind][] +using [custom values][]. + +Note that this configuration should be used for test only and isn't recommended +for production. + +Note that Kind < 0.7.0 are affected by a [kind issue][] with mount points +created from PVCs not writable by non-root users. [kubernetes-sigs/kind#1157][] +fix it in Kind 0.7.0. + +The workaround for Kind < 0.7.0 is to install manually +[Rancher Local Path Provisioner][] and use `local-path` storage class for +Elasticsearch volumes (see [Makefile][] instructions). + + +## Usage + +* For Kind >= 0.7.0: Deploy Elasticsearch chart with the default values: `make install` +* For Kind < 0.7.0: Deploy Elasticsearch chart with `local-path` storage class: `make install-local-path` + +* You can now setup a port forward to query Elasticsearch API: + + ``` + kubectl port-forward svc/elasticsearch-master 9200 + curl localhost:9200/_cat/indices + ``` + + +[custom values]: https://github.com/elastic/helm-charts/blob/main/elasticsearch/examples/kubernetes-kind/values.yaml +[kind]: https://kind.sigs.k8s.io/ +[kind issue]: https://github.com/kubernetes-sigs/kind/issues/830 +[kubernetes-sigs/kind#1157]: https://github.com/kubernetes-sigs/kind/pull/1157 +[rancher local path provisioner]: https://github.com/rancher/local-path-provisioner +[Makefile]: https://github.com/elastic/helm-charts/blob/main/elasticsearch/examples/kubernetes-kind/Makefile diff --git a/elasticsearch/examples/kubernetes-kind/values-local-path.yaml b/elasticsearch/examples/kubernetes-kind/values-local-path.yaml new file mode 100644 index 0000000..500ad4b --- /dev/null +++ b/elasticsearch/examples/kubernetes-kind/values-local-path.yaml @@ -0,0 +1,23 @@ +--- +# Permit co-located instances for solitary minikube virtual machines. +antiAffinity: "soft" + +# Shrink default JVM heap. +esJavaOpts: "-Xmx128m -Xms128m" + +# Allocate smaller chunks of memory per pod. +resources: + requests: + cpu: "100m" + memory: "512M" + limits: + cpu: "1000m" + memory: "512M" + +# Request smaller persistent volumes. +volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "local-path" + resources: + requests: + storage: 100M diff --git a/elasticsearch/examples/kubernetes-kind/values.yaml b/elasticsearch/examples/kubernetes-kind/values.yaml new file mode 100644 index 0000000..500ad4b --- /dev/null +++ b/elasticsearch/examples/kubernetes-kind/values.yaml @@ -0,0 +1,23 @@ +--- +# Permit co-located instances for solitary minikube virtual machines. +antiAffinity: "soft" + +# Shrink default JVM heap. +esJavaOpts: "-Xmx128m -Xms128m" + +# Allocate smaller chunks of memory per pod. +resources: + requests: + cpu: "100m" + memory: "512M" + limits: + cpu: "1000m" + memory: "512M" + +# Request smaller persistent volumes. +volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "local-path" + resources: + requests: + storage: 100M diff --git a/elasticsearch/examples/microk8s/Makefile b/elasticsearch/examples/microk8s/Makefile new file mode 100644 index 0000000..2d0012d --- /dev/null +++ b/elasticsearch/examples/microk8s/Makefile @@ -0,0 +1,13 @@ +default: test + +RELEASE := helm-es-microk8s +TIMEOUT := 1200s + +install: + helm upgrade --wait --timeout=$(TIMEOUT) --install --values values.yaml $(RELEASE) ../../ + +test: install + helm test $(RELEASE) + +purge: + helm del $(RELEASE) diff --git a/elasticsearch/examples/microk8s/README.md b/elasticsearch/examples/microk8s/README.md new file mode 100644 index 0000000..db5d658 --- /dev/null +++ b/elasticsearch/examples/microk8s/README.md @@ -0,0 +1,32 @@ +# MicroK8S + +This example deploy a 3 nodes Elasticsearch 8.5.1 cluster on [MicroK8S][] +using [custom values][]. + +Note that this configuration should be used for test only and isn't recommended +for production. + + +## Requirements + +The following MicroK8S [addons][] need to be enabled: +- `dns` +- `helm` +- `storage` + + +## Usage + +* Deploy Elasticsearch chart with the default values: `make install` + +* You can now setup a port forward to query Elasticsearch API: + + ``` + kubectl port-forward svc/elasticsearch-master 9200 + curl localhost:9200/_cat/indices + ``` + + +[addons]: https://microk8s.io/docs/addons +[custom values]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/microk8s/values.yaml +[MicroK8S]: https://microk8s.io diff --git a/elasticsearch/examples/microk8s/values.yaml b/elasticsearch/examples/microk8s/values.yaml new file mode 100644 index 0000000..2627ecb --- /dev/null +++ b/elasticsearch/examples/microk8s/values.yaml @@ -0,0 +1,32 @@ +--- +# Disable privileged init Container creation. +sysctlInitContainer: + enabled: false + +# Restrict the use of the memory-mapping when sysctlInitContainer is disabled. +esConfig: + elasticsearch.yml: | + node.store.allow_mmap: false + +# Permit co-located instances for solitary minikube virtual machines. +antiAffinity: "soft" + +# Shrink default JVM heap. +esJavaOpts: "-Xmx128m -Xms128m" + +# Allocate smaller chunks of memory per pod. +resources: + requests: + cpu: "100m" + memory: "512M" + limits: + cpu: "1000m" + memory: "512M" + +# Request smaller persistent volumes. +volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "microk8s-hostpath" + resources: + requests: + storage: 100M diff --git a/elasticsearch/examples/migration/Makefile b/elasticsearch/examples/migration/Makefile new file mode 100644 index 0000000..020906f --- /dev/null +++ b/elasticsearch/examples/migration/Makefile @@ -0,0 +1,10 @@ +PREFIX := helm-es-migration + +data: + helm upgrade --wait --timeout=$(TIMEOUT) --install --values data.yaml $(PREFIX)-data ../../ + +master: + helm upgrade --wait --timeout=$(TIMEOUT) --install --values master.yaml $(PREFIX)-master ../../ + +client: + helm upgrade --wait --timeout=$(TIMEOUT) --install --values client.yaml $(PREFIX)-client ../../ diff --git a/elasticsearch/examples/migration/README.md b/elasticsearch/examples/migration/README.md new file mode 100644 index 0000000..8124dca --- /dev/null +++ b/elasticsearch/examples/migration/README.md @@ -0,0 +1,167 @@ +# Migration Guide from helm/charts + +There are two viable options for migrating from the community Elasticsearch Helm +chart from the [helm/charts][] repo. + +1. Restoring from Snapshot to a fresh cluster +2. Live migration by joining a new cluster to the existing cluster. + +## Restoring from Snapshot + +This is the recommended and preferred option. The downside is that it will +involve a period of write downtime during the migration. If you have a way to +temporarily stop writes to your cluster then this is the way to go. This is also +a lot simpler as it just involves launching a fresh cluster and restoring a +snapshot following the [restoring to a different cluster guide][]. + +## Live migration + +If restoring from a snapshot is not possible due to the write downtime then a +live migration is also possible. It is very important to first test this in a +testing environment to make sure you are comfortable with the process and fully +understand what is happening. + +This process will involve joining a new set of master, data and client nodes to +an existing cluster that has been deployed using the [helm/charts][] community +chart. Nodes will then be replaced one by one in a controlled fashion to +decommission the old cluster. + +This example will be using the default values for the existing helm/charts +release and for the Elastic helm-charts release. If you have changed any of the +default values then you will need to first make sure that your values are +configured in a compatible way before starting the migration. + +The process will involve a re-sync and a rolling restart of all of your data +nodes. Therefore it is important to disable shard allocation and perform a synced +flush like you normally would during any other rolling upgrade. See the +[rolling upgrades guide][] for more information. + +* The default image for this chart is +`docker.elastic.co/elasticsearch/elasticsearch` which contains the default +distribution of Elasticsearch with a [basic license][]. Make sure to update the +`image` and `imageTag` values to the correct Docker image and Elasticsearch +version that you currently have deployed. + +* Convert your current helm/charts configuration into something that is +compatible with this chart. + +* Take a fresh snapshot of your cluster. If something goes wrong you want to be +able to restore your data no matter what. + +* Check that your clusters health is green. If not abort and make sure your +cluster is healthy before continuing: + + ``` + curl localhost:9200/_cluster/health + ``` + +* Deploy new data nodes which will join the existing cluster. Take a look at the +configuration in [data.yaml][]: + + ``` + make data + ``` + +* Check that the new nodes have joined the cluster (run this and any other curl +commands from within one of your pods): + + ``` + curl localhost:9200/_cat/nodes + ``` + +* Check that your cluster is still green. If so we can now start to scale down +the existing data nodes. Assuming you have the default amount of data nodes (2) +we now want to scale it down to 1: + + ``` + kubectl scale statefulsets my-release-elasticsearch-data --replicas=1 + ``` + +* Wait for your cluster to become green again: + + ``` + watch 'curl -s localhost:9200/_cluster/health' + ``` + +* Once the cluster is green we can scale down again: + + ``` + kubectl scale statefulsets my-release-elasticsearch-data --replicas=0 + ``` + +* Wait for the cluster to be green again. +* OK. We now have all data nodes running in the new cluster. Time to replace the +masters by firstly scaling down the masters from 3 to 2. Between each step make +sure to wait for the cluster to become green again, and check with +`curl localhost:9200/_cat/nodes` that you see the correct amount of master +nodes. During this process we will always make sure to keep at least 2 master +nodes as to not lose quorum: + + ``` + kubectl scale statefulsets my-release-elasticsearch-master --replicas=2 + ``` + +* Now deploy a single new master so that we have 3 masters again. See +[master.yaml][] for the configuration: + + ``` + make master + ``` + +* Scale down old masters to 1: + + ``` + kubectl scale statefulsets my-release-elasticsearch-master --replicas=1 + ``` + +* Edit the masters in [masters.yaml][] to 2 and redeploy: + + ``` + make master + ``` + +* Scale down the old masters to 0: + + ``` + kubectl scale statefulsets my-release-elasticsearch-master --replicas=0 + ``` + +* Edit the [masters.yaml][] to have 3 replicas and remove the +`discovery.zen.ping.unicast.hosts` entry from `extraEnvs` then redeploy the +masters. This will make sure all 3 masters are running in the new cluster and +are pointing at each other for discovery: + + ``` + make master + ``` + +* Remove the `discovery.zen.ping.unicast.hosts` entry from `extraEnvs` then +redeploy the data nodes to make sure they are pointing at the new masters: + + ``` + make data + ``` + +* Deploy the client nodes: + + ``` + make client + ``` + +* Update any processes that are talking to the existing client nodes and point +them to the new client nodes. Once this is done you can scale down the old +client nodes: + + ``` + kubectl scale deployment my-release-elasticsearch-client --replicas=0 + ``` + +* The migration should now be complete. After verifying that everything is +working correctly you can cleanup leftover resources from your old cluster. + +[basic license]: https://www.elastic.co/subscriptions +[data.yaml]: https://github.com/elastic/helm-charts/blob/main/elasticsearch/examples/migration/data.yaml +[helm/charts]: https://github.com/helm/charts/tree/master/stable/elasticsearch +[master.yaml]: https://github.com/elastic/helm-charts/blob/main/elasticsearch/examples/migration/master.yaml +[restoring to a different cluster guide]: https://www.elastic.co/guide/en/elasticsearch/reference/6.8/modules-snapshots.html#_restoring_to_a_different_cluster +[rolling upgrades guide]: https://www.elastic.co/guide/en/elasticsearch/reference/6.8/rolling-upgrades.html diff --git a/elasticsearch/examples/migration/client.yaml b/elasticsearch/examples/migration/client.yaml new file mode 100644 index 0000000..8ac0641 --- /dev/null +++ b/elasticsearch/examples/migration/client.yaml @@ -0,0 +1,19 @@ +--- +replicas: 2 + +clusterName: "elasticsearch" +nodeGroup: "client" + +esMajorVersion: 6 + +roles: [] + +volumeClaimTemplate: + accessModes: ["ReadWriteOnce"] + storageClassName: "standard" + resources: + requests: + storage: 1Gi # Currently needed till pvcs are made optional + +persistence: + enabled: false diff --git a/elasticsearch/examples/migration/data.yaml b/elasticsearch/examples/migration/data.yaml new file mode 100644 index 0000000..012569d --- /dev/null +++ b/elasticsearch/examples/migration/data.yaml @@ -0,0 +1,14 @@ +--- +replicas: 2 + +esMajorVersion: 6 + +extraEnvs: + - name: discovery.zen.ping.unicast.hosts + value: "my-release-elasticsearch-discovery" + +clusterName: "elasticsearch" +nodeGroup: "data" + +roles: + - data diff --git a/elasticsearch/examples/migration/master.yaml b/elasticsearch/examples/migration/master.yaml new file mode 100644 index 0000000..9f2f609 --- /dev/null +++ b/elasticsearch/examples/migration/master.yaml @@ -0,0 +1,23 @@ +--- +# Temporarily set to 3 so we can scale up/down the old a new cluster +# one at a time whilst always keeping 3 masters running +replicas: 1 + +esMajorVersion: 6 + +extraEnvs: + - name: discovery.zen.ping.unicast.hosts + value: "my-release-elasticsearch-discovery" + +clusterName: "elasticsearch" +nodeGroup: "master" + +roles: + - master + +volumeClaimTemplate: + accessModes: ["ReadWriteOnce"] + storageClassName: "standard" + resources: + requests: + storage: 4Gi diff --git a/elasticsearch/examples/minikube/Makefile b/elasticsearch/examples/minikube/Makefile new file mode 100644 index 0000000..1021d98 --- /dev/null +++ b/elasticsearch/examples/minikube/Makefile @@ -0,0 +1,13 @@ +default: test + +RELEASE := helm-es-minikube +TIMEOUT := 1200s + +install: + helm upgrade --wait --timeout=$(TIMEOUT) --install --values values.yaml $(RELEASE) ../../ + +test: install + helm test $(RELEASE) + +purge: + helm del $(RELEASE) diff --git a/elasticsearch/examples/minikube/README.md b/elasticsearch/examples/minikube/README.md new file mode 100644 index 0000000..5d7e6e2 --- /dev/null +++ b/elasticsearch/examples/minikube/README.md @@ -0,0 +1,38 @@ +# Minikube + +This example deploy a 3 nodes Elasticsearch 8.5.1 cluster on [Minikube][] +using [custom values][]. + +If helm or kubectl timeouts occur, you may consider creating a minikube VM with +more CPU cores or memory allocated. + +Note that this configuration should be used for test only and isn't recommended +for production. + + +## Requirements + +In order to properly support the required persistent volume claims for the +Elasticsearch StatefulSet, the `default-storageclass` and `storage-provisioner` +minikube addons must be enabled. + +``` +minikube addons enable default-storageclass +minikube addons enable storage-provisioner +``` + + +## Usage + +* Deploy Elasticsearch chart with the default values: `make install` + +* You can now setup a port forward to query Elasticsearch API: + + ``` + kubectl port-forward svc/elasticsearch-master 9200 + curl localhost:9200/_cat/indices + ``` + + +[custom values]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/minikube/values.yaml +[minikube]: https://minikube.sigs.k8s.io/docs/ diff --git a/elasticsearch/examples/minikube/values.yaml b/elasticsearch/examples/minikube/values.yaml new file mode 100644 index 0000000..ccceb3a --- /dev/null +++ b/elasticsearch/examples/minikube/values.yaml @@ -0,0 +1,23 @@ +--- +# Permit co-located instances for solitary minikube virtual machines. +antiAffinity: "soft" + +# Shrink default JVM heap. +esJavaOpts: "-Xmx128m -Xms128m" + +# Allocate smaller chunks of memory per pod. +resources: + requests: + cpu: "100m" + memory: "512M" + limits: + cpu: "1000m" + memory: "512M" + +# Request smaller persistent volumes. +volumeClaimTemplate: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "standard" + resources: + requests: + storage: 100M diff --git a/elasticsearch/examples/multi/Makefile b/elasticsearch/examples/multi/Makefile new file mode 100644 index 0000000..243e504 --- /dev/null +++ b/elasticsearch/examples/multi/Makefile @@ -0,0 +1,19 @@ +default: test + +include ../../../helpers/examples.mk + +PREFIX := helm-es-multi +RELEASE := helm-es-multi-master +TIMEOUT := 1200s + +install: + helm upgrade --wait --timeout=$(TIMEOUT) --install --values master.yaml $(PREFIX)-master ../../ + helm upgrade --wait --timeout=$(TIMEOUT) --install --values data.yaml $(PREFIX)-data ../../ + helm upgrade --wait --timeout=$(TIMEOUT) --install --values client.yaml $(PREFIX)-client ../../ + +test: install goss + +purge: + helm del $(PREFIX)-master + helm del $(PREFIX)-data + helm del $(PREFIX)-client diff --git a/elasticsearch/examples/multi/README.md b/elasticsearch/examples/multi/README.md new file mode 100644 index 0000000..bfc5e30 --- /dev/null +++ b/elasticsearch/examples/multi/README.md @@ -0,0 +1,29 @@ +# Multi + +This example deploy an Elasticsearch 8.5.1 cluster composed of 3 different Helm +releases: + +- `helm-es-multi-master` for the 3 master nodes using [master values][] +- `helm-es-multi-data` for the 3 data nodes using [data values][] +- `helm-es-multi-client` for the 3 client nodes using [client values][] + +## Usage + +* Deploy the 3 Elasticsearch releases: `make install` + +* You can now setup a port forward to query Elasticsearch API: + + ``` + kubectl port-forward svc/multi-master 9200 + curl -u elastic:changeme http://localhost:9200/_cat/indices + ``` + +## Testing + +You can also run [goss integration tests][] using `make test` + + +[client values]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/multi/client.yaml +[data values]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/multi/data.yaml +[goss integration tests]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/multi/test/goss.yaml +[master values]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/multi/master.yaml diff --git a/elasticsearch/examples/multi/client.yaml b/elasticsearch/examples/multi/client.yaml new file mode 100644 index 0000000..2c05d1e --- /dev/null +++ b/elasticsearch/examples/multi/client.yaml @@ -0,0 +1,50 @@ +--- +clusterName: "multi" +nodeGroup: "client" + +extraEnvs: + - name: ELASTIC_PASSWORD + valueFrom: + secretKeyRef: + name: multi-master-credentials + key: password + - name: xpack.security.enabled + value: "true" + - name: xpack.security.transport.ssl.enabled + value: "true" + - name: xpack.security.http.ssl.enabled + value: "true" + - name: xpack.security.transport.ssl.verification_mode + value: "certificate" + - name: xpack.security.transport.ssl.key + value: "/usr/share/elasticsearch/config/certs/tls.key" + - name: xpack.security.transport.ssl.certificate + value: "/usr/share/elasticsearch/config/certs/tls.crt" + - name: xpack.security.transport.ssl.certificate_authorities + value: "/usr/share/elasticsearch/config/certs/ca.crt" + - name: xpack.security.http.ssl.key + value: "/usr/share/elasticsearch/config/certs/tls.key" + - name: xpack.security.http.ssl.certificate + value: "/usr/share/elasticsearch/config/certs/tls.crt" + - name: xpack.security.http.ssl.certificate_authorities + value: "/usr/share/elasticsearch/config/certs/ca.crt" + +roles: [] + +persistence: + enabled: false + +# For client nodes, we also need to add an empty node.roles in elasticsearch.yml +# This is due to https://github.com/elastic/helm-charts/pull/1186#discussion_r631225687 +esConfig: + elasticsearch.yml: | + node.roles: [] + +secret: + enabled: false + +createCert: false +secretMounts: + - name: elastic-certificates + secretName: multi-master-certs + path: /usr/share/elasticsearch/config/certs diff --git a/elasticsearch/examples/multi/data.yaml b/elasticsearch/examples/multi/data.yaml new file mode 100644 index 0000000..cd453d3 --- /dev/null +++ b/elasticsearch/examples/multi/data.yaml @@ -0,0 +1,48 @@ +--- +clusterName: "multi" +nodeGroup: "data" + +extraEnvs: + - name: ELASTIC_PASSWORD + valueFrom: + secretKeyRef: + name: multi-master-credentials + key: password + - name: xpack.security.enabled + value: "true" + - name: xpack.security.transport.ssl.enabled + value: "true" + - name: xpack.security.http.ssl.enabled + value: "true" + - name: xpack.security.transport.ssl.verification_mode + value: "certificate" + - name: xpack.security.transport.ssl.key + value: "/usr/share/elasticsearch/config/certs/tls.key" + - name: xpack.security.transport.ssl.certificate + value: "/usr/share/elasticsearch/config/certs/tls.crt" + - name: xpack.security.transport.ssl.certificate_authorities + value: "/usr/share/elasticsearch/config/certs/ca.crt" + - name: xpack.security.http.ssl.key + value: "/usr/share/elasticsearch/config/certs/tls.key" + - name: xpack.security.http.ssl.certificate + value: "/usr/share/elasticsearch/config/certs/tls.crt" + - name: xpack.security.http.ssl.certificate_authorities + value: "/usr/share/elasticsearch/config/certs/ca.crt" + +roles: + - data + - data_content + - data_hot + - data_warm + - data_cold + - data_frozen + - ingest + +secret: + enabled: false + +createCert: false +secretMounts: + - name: elastic-certificates + secretName: multi-master-certs + path: /usr/share/elasticsearch/config/certs diff --git a/elasticsearch/examples/multi/master.yaml b/elasticsearch/examples/multi/master.yaml new file mode 100644 index 0000000..bb4ea30 --- /dev/null +++ b/elasticsearch/examples/multi/master.yaml @@ -0,0 +1,6 @@ +--- +clusterName: "multi" +nodeGroup: "master" + +roles: + - master diff --git a/elasticsearch/examples/multi/test/goss.yaml b/elasticsearch/examples/multi/test/goss.yaml new file mode 100644 index 0000000..c365388 --- /dev/null +++ b/elasticsearch/examples/multi/test/goss.yaml @@ -0,0 +1,12 @@ +http: + https://localhost:9200/_cluster/health: + status: 200 + timeout: 2000 + allow-insecure: true + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + body: + - "green" + - '"cluster_name":"multi"' + - '"number_of_nodes":9' + - '"number_of_data_nodes":3' diff --git a/elasticsearch/examples/networkpolicy/Makefile b/elasticsearch/examples/networkpolicy/Makefile new file mode 100644 index 0000000..e7b20c5 --- /dev/null +++ b/elasticsearch/examples/networkpolicy/Makefile @@ -0,0 +1,14 @@ +default: test + +include ../../../helpers/examples.mk + +RELEASE := helm-es-networkpolicy +TIMEOUT := 1200s + +install: + helm upgrade --wait --timeout=$(TIMEOUT) --install --values values.yaml $(RELEASE) ../../ + +test: install goss + +purge: + helm del $(RELEASE) diff --git a/elasticsearch/examples/networkpolicy/values.yaml b/elasticsearch/examples/networkpolicy/values.yaml new file mode 100644 index 0000000..1963d20 --- /dev/null +++ b/elasticsearch/examples/networkpolicy/values.yaml @@ -0,0 +1,37 @@ +networkPolicy: + http: + enabled: true + explicitNamespacesSelector: + # Accept from namespaces with all those different rules (from whitelisted Pods) + matchLabels: + role: frontend-http + matchExpressions: + - {key: role, operator: In, values: [frontend-http]} + additionalRules: + - podSelector: + matchLabels: + role: frontend-http + - podSelector: + matchExpressions: + - key: role + operator: In + values: + - frontend-http + transport: + enabled: true + allowExternal: true + explicitNamespacesSelector: + matchLabels: + role: frontend-transport + matchExpressions: + - {key: role, operator: In, values: [frontend-transport]} + additionalRules: + - podSelector: + matchLabels: + role: frontend-transport + - podSelector: + matchExpressions: + - key: role + operator: In + values: + - frontend-transport diff --git a/elasticsearch/examples/openshift/Makefile b/elasticsearch/examples/openshift/Makefile new file mode 100644 index 0000000..078c33c --- /dev/null +++ b/elasticsearch/examples/openshift/Makefile @@ -0,0 +1,13 @@ +default: test + +include ../../../helpers/examples.mk + +RELEASE := elasticsearch + +install: + helm upgrade --wait --timeout=$(TIMEOUT) --install --values values.yaml $(RELEASE) ../../ + +test: install goss + +purge: + helm del $(RELEASE) diff --git a/elasticsearch/examples/openshift/README.md b/elasticsearch/examples/openshift/README.md new file mode 100644 index 0000000..22ccf72 --- /dev/null +++ b/elasticsearch/examples/openshift/README.md @@ -0,0 +1,24 @@ +# OpenShift + +This example deploy a 3 nodes Elasticsearch 8.5.1 cluster on [OpenShift][] +using [custom values][]. + +## Usage + +* Deploy Elasticsearch chart with the default values: `make install` + +* You can now setup a port forward to query Elasticsearch API: + + ``` + kubectl port-forward svc/elasticsearch-master 9200 + curl localhost:9200/_cat/indices + ``` + +## Testing + +You can also run [goss integration tests][] using `make test` + + +[custom values]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/openshift/values.yaml +[goss integration tests]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/openshift/test/goss.yaml +[openshift]: https://www.openshift.com/ diff --git a/elasticsearch/examples/openshift/test/goss.yaml b/elasticsearch/examples/openshift/test/goss.yaml new file mode 100644 index 0000000..af536ec --- /dev/null +++ b/elasticsearch/examples/openshift/test/goss.yaml @@ -0,0 +1,20 @@ +http: + https://localhost:9200/_cluster/health: + status: 200 + timeout: 2000 + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + body: + - "green" + - '"number_of_nodes":3' + - '"number_of_data_nodes":3' + + https://localhost:9200: + status: 200 + timeout: 2000 + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + body: + - '"number" : "8.5.1"' + - '"cluster_name" : "elasticsearch"' + - "You Know, for Search" diff --git a/elasticsearch/examples/openshift/values.yaml b/elasticsearch/examples/openshift/values.yaml new file mode 100644 index 0000000..8a21126 --- /dev/null +++ b/elasticsearch/examples/openshift/values.yaml @@ -0,0 +1,11 @@ +--- + +securityContext: + runAsUser: null + +podSecurityContext: + fsGroup: null + runAsUser: null + +sysctlInitContainer: + enabled: false diff --git a/elasticsearch/examples/security/Makefile b/elasticsearch/examples/security/Makefile new file mode 100644 index 0000000..78726e6 --- /dev/null +++ b/elasticsearch/examples/security/Makefile @@ -0,0 +1,36 @@ +default: test + +include ../../../helpers/examples.mk + +RELEASE := helm-es-security +ELASTICSEARCH_IMAGE := docker.elastic.co/elasticsearch/elasticsearch:$(STACK_VERSION) +TIMEOUT := 1200s + +install: + helm upgrade --wait --timeout=$(TIMEOUT) --install --values values.yaml $(RELEASE) ../../ + +test: secrets install goss + +purge: + kubectl delete secrets elastic-certificates elastic-certificate-pem elastic-certificate-crt|| true + helm del $(RELEASE) + +pull-elasticsearch-image: + docker pull $(ELASTICSEARCH_IMAGE) + +secrets: + docker rm -f elastic-helm-charts-certs || true + rm -f elastic-certificates.p12 elastic-certificate.pem elastic-certificate.crt elastic-stack-ca.p12 || true + docker run --name elastic-helm-charts-certs -i -w /tmp \ + $(ELASTICSEARCH_IMAGE) \ + /bin/sh -c " \ + elasticsearch-certutil ca --out /tmp/elastic-stack-ca.p12 --pass '' && \ + elasticsearch-certutil cert --name security-master --dns security-master --ca /tmp/elastic-stack-ca.p12 --pass '' --ca-pass '' --out /tmp/elastic-certificates.p12" && \ + docker cp elastic-helm-charts-certs:/tmp/elastic-certificates.p12 ./ && \ + docker rm -f elastic-helm-charts-certs && \ + openssl pkcs12 -nodes -passin pass:'' -in elastic-certificates.p12 -out elastic-certificate.pem && \ + openssl x509 -outform der -in elastic-certificate.pem -out elastic-certificate.crt && \ + kubectl create secret generic elastic-certificates --from-file=elastic-certificates.p12 && \ + kubectl create secret generic elastic-certificate-pem --from-file=elastic-certificate.pem && \ + kubectl create secret generic elastic-certificate-crt --from-file=elastic-certificate.crt && \ + rm -f elastic-certificates.p12 elastic-certificate.pem elastic-certificate.crt elastic-stack-ca.p12 diff --git a/elasticsearch/examples/security/README.md b/elasticsearch/examples/security/README.md new file mode 100644 index 0000000..328fefa --- /dev/null +++ b/elasticsearch/examples/security/README.md @@ -0,0 +1,29 @@ +# Security + +This example deploy a 3 nodes Elasticsearch 8.5.1 with authentication and +autogenerated certificates for TLS (see [values][]). + +Note that this configuration should be used for test only. For a production +deployment you should generate SSL certificates following the [official docs][]. + +## Usage + +* Create the required secrets: `make secrets` + +* Deploy Elasticsearch chart with the default values: `make install` + +* You can now setup a port forward to query Elasticsearch API: + + ``` + kubectl port-forward svc/security-master 9200 + curl -u elastic:changeme https://localhost:9200/_cat/indices + ``` + +## Testing + +You can also run [goss integration tests][] using `make test` + + +[goss integration tests]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/security/test/goss.yaml +[official docs]: https://www.elastic.co/guide/en/elasticsearch/reference/current/configuring-tls.html#node-certificates +[values]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/security/values.yaml diff --git a/elasticsearch/examples/security/test/goss.yaml b/elasticsearch/examples/security/test/goss.yaml new file mode 100644 index 0000000..e35393f --- /dev/null +++ b/elasticsearch/examples/security/test/goss.yaml @@ -0,0 +1,44 @@ +http: + https://security-master:9200/_cluster/health: + status: 200 + timeout: 2000 + allow-insecure: true + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + body: + - "green" + - '"number_of_nodes":3' + - '"number_of_data_nodes":3' + + https://localhost:9200/: + status: 200 + timeout: 2000 + allow-insecure: true + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + body: + - '"cluster_name" : "security"' + - "You Know, for Search" + + https://localhost:9200/_license: + status: 200 + timeout: 2000 + allow-insecure: true + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + body: + - "active" + - "basic" + +file: + /usr/share/elasticsearch/config/elasticsearch.yml: + exists: true + contains: + - "xpack.security.enabled: true" + - "xpack.security.transport.ssl.enabled: true" + - "xpack.security.transport.ssl.verification_mode: certificate" + - "xpack.security.transport.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12" + - "xpack.security.transport.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12" + - "xpack.security.http.ssl.enabled: true" + - "xpack.security.http.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12" + - "xpack.security.http.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12" diff --git a/elasticsearch/examples/security/values.yaml b/elasticsearch/examples/security/values.yaml new file mode 100644 index 0000000..e2b1c18 --- /dev/null +++ b/elasticsearch/examples/security/values.yaml @@ -0,0 +1,28 @@ +--- +clusterName: "security" +nodeGroup: "master" + +createCert: false + +roles: + - master + - ingest + - data + +protocol: https + +esConfig: + elasticsearch.yml: | + xpack.security.enabled: true + xpack.security.transport.ssl.enabled: true + xpack.security.transport.ssl.verification_mode: certificate + xpack.security.transport.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + xpack.security.transport.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + xpack.security.http.ssl.enabled: true + xpack.security.http.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + xpack.security.http.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12 + +secretMounts: + - name: elastic-certificates + secretName: elastic-certificates + path: /usr/share/elasticsearch/config/certs diff --git a/elasticsearch/examples/upgrade/Makefile b/elasticsearch/examples/upgrade/Makefile new file mode 100644 index 0000000..0bfddab --- /dev/null +++ b/elasticsearch/examples/upgrade/Makefile @@ -0,0 +1,19 @@ +default: test + +include ../../../helpers/examples.mk + +CHART := elasticsearch +RELEASE := helm-es-upgrade +FROM := 7.17.1 # upgrade from versions before 7.17.1 isn't compatible with 8.x + +install: + ../../../helpers/upgrade.sh --chart $(CHART) --release $(RELEASE) --from $(FROM) + # Rolling upgrade doesn't work when upgrading from clusters with security disabled. + # This is because nodes with security enabled can't join a cluster with security disabled. + # Every nodes need to be recreated at the same time so they can recreate a cluster with security enabled + kubectl delete pod --selector=app=upgrade-master + +test: install goss + +purge: + helm del $(RELEASE) diff --git a/elasticsearch/examples/upgrade/README.md b/elasticsearch/examples/upgrade/README.md new file mode 100644 index 0000000..ab19df7 --- /dev/null +++ b/elasticsearch/examples/upgrade/README.md @@ -0,0 +1,17 @@ +# Upgrade + +This example will deploy a 3 node Elasticsearch cluster chart using an old chart +version, then upgrade it. + + +## Usage + +* Deploy and upgrade Elasticsearch chart with the default values: `make install` + + +## Testing + +You can also run [goss integration tests][] using `make test`. + + +[goss integration tests]: https://github.com/elastic/helm-charts/tree/main/elasticsearch/examples/upgrade/test/goss.yaml diff --git a/elasticsearch/examples/upgrade/test/goss.yaml b/elasticsearch/examples/upgrade/test/goss.yaml new file mode 100644 index 0000000..b730456 --- /dev/null +++ b/elasticsearch/examples/upgrade/test/goss.yaml @@ -0,0 +1,22 @@ +http: + https://localhost:9200/_cluster/health: + status: 200 + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + allow-insecure: true + timeout: 2000 + body: + - "green" + - '"number_of_nodes":3' + - '"number_of_data_nodes":3' + + https://localhost:9200: + status: 200 + username: elastic + password: "{{ .Env.ELASTIC_PASSWORD }}" + allow-insecure: true + timeout: 2000 + body: + - '"number" : "8.5.1"' + - '"cluster_name" : "upgrade"' + - "You Know, for Search" diff --git a/elasticsearch/examples/upgrade/values.yaml b/elasticsearch/examples/upgrade/values.yaml new file mode 100644 index 0000000..461b100 --- /dev/null +++ b/elasticsearch/examples/upgrade/values.yaml @@ -0,0 +1,6 @@ +--- +clusterName: upgrade +# Rolling upgrade doesn't work when upgrading from clusters with security disabled. +# This is because nodes with security enabled can't join a cluster with security disabled. +# Every nodes need to be recreated at the same time so they can recreate a cluster with security enabled +updateStrategy: OnDelete diff --git a/elasticsearch/templates/NOTES.txt b/elasticsearch/templates/NOTES.txt new file mode 100644 index 0000000..752526f --- /dev/null +++ b/elasticsearch/templates/NOTES.txt @@ -0,0 +1,8 @@ +1. Watch all cluster members come up. + $ kubectl get pods --namespace={{ .Release.Namespace }} -l app={{ template "elasticsearch.uname" . }} -w +2. Retrieve elastic user's password. + $ kubectl get secrets --namespace={{ .Release.Namespace }} {{ template "elasticsearch.uname" . }}-credentials -ojsonpath='{.data.password}' | base64 -d +{{- if .Values.tests.enabled }} +3. Test cluster health using Helm test. + $ helm --namespace={{ .Release.Namespace }} test {{ .Release.Name }} +{{- end -}} diff --git a/elasticsearch/templates/_helpers.tpl b/elasticsearch/templates/_helpers.tpl new file mode 100644 index 0000000..b47e2fe --- /dev/null +++ b/elasticsearch/templates/_helpers.tpl @@ -0,0 +1,97 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "elasticsearch.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). +*/}} +{{- define "elasticsearch.fullname" -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- define "elasticsearch.uname" -}} +{{- if empty .Values.fullnameOverride -}} +{{- if empty .Values.nameOverride -}} +{{ .Values.clusterName }}-{{ .Values.nodeGroup }} +{{- else -}} +{{ .Values.nameOverride }}-{{ .Values.nodeGroup }} +{{- end -}} +{{- else -}} +{{ .Values.fullnameOverride }} +{{- end -}} +{{- end -}} + +{{/* +Generate certificates when the secret doesn't exist +*/}} +{{- define "elasticsearch.gen-certs" -}} +{{- $certs := lookup "v1" "Secret" .Release.Namespace ( printf "%s-certs" (include "elasticsearch.uname" . ) ) -}} +{{- if $certs -}} +tls.crt: {{ index $certs.data "tls.crt" }} +tls.key: {{ index $certs.data "tls.key" }} +ca.crt: {{ index $certs.data "ca.crt" }} +{{- else -}} +{{- $altNames := list ( include "elasticsearch.masterService" . ) ( printf "%s.%s" (include "elasticsearch.masterService" .) .Release.Namespace ) ( printf "%s.%s.svc" (include "elasticsearch.masterService" .) .Release.Namespace ) -}} +{{- $ca := genCA "elasticsearch-ca" 365 -}} +{{- $cert := genSignedCert ( include "elasticsearch.masterService" . ) nil $altNames 365 $ca -}} +tls.crt: {{ $cert.Cert | toString | b64enc }} +tls.key: {{ $cert.Key | toString | b64enc }} +ca.crt: {{ $ca.Cert | toString | b64enc }} +{{- end -}} +{{- end -}} + +{{- define "elasticsearch.masterService" -}} +{{- if empty .Values.masterService -}} +{{- if empty .Values.fullnameOverride -}} +{{- if empty .Values.nameOverride -}} +{{ .Values.clusterName }}-master +{{- else -}} +{{ .Values.nameOverride }}-master +{{- end -}} +{{- else -}} +{{ .Values.fullnameOverride }} +{{- end -}} +{{- else -}} +{{ .Values.masterService }} +{{- end -}} +{{- end -}} + +{{- define "elasticsearch.endpoints" -}} +{{- $replicas := int (toString (.Values.replicas)) }} +{{- $uname := (include "elasticsearch.uname" .) }} + {{- range $i, $e := untilStep 0 $replicas 1 -}} +{{ $uname }}-{{ $i }}, + {{- end -}} +{{- end -}} + +{{- define "elasticsearch.roles" -}} +{{- range $.Values.roles -}} +{{ . }}, +{{- end -}} +{{- end -}} + +{{- define "elasticsearch.esMajorVersion" -}} +{{- if .Values.esMajorVersion -}} +{{ .Values.esMajorVersion }} +{{- else -}} +{{- $version := int (index (.Values.imageTag | splitList ".") 0) -}} + {{- if and (contains "docker.elastic.co/elasticsearch/elasticsearch" .Values.image) (not (eq $version 0)) -}} +{{ $version }} + {{- else -}} +8 + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Use the fullname if the serviceAccount value is not set +*/}} +{{- define "elasticsearch.serviceAccount" -}} +{{- .Values.rbac.serviceAccountName | default (include "elasticsearch.uname" .) -}} +{{- end -}} diff --git a/elasticsearch/templates/configmap.yaml b/elasticsearch/templates/configmap.yaml new file mode 100644 index 0000000..fd1ad30 --- /dev/null +++ b/elasticsearch/templates/configmap.yaml @@ -0,0 +1,34 @@ +{{- if .Values.esConfig }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "elasticsearch.uname" . }}-config + labels: + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}" + app: "{{ template "elasticsearch.uname" . }}" +data: +{{- range $path, $config := .Values.esConfig }} + {{ $path }}: | +{{ $config | indent 4 -}} +{{- end -}} +{{- end -}} +{{- if .Values.esJvmOptions }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "elasticsearch.uname" . }}-jvm-options + labels: + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}" + app: "{{ template "elasticsearch.uname" . }}" +data: +{{- range $path, $config := .Values.esJvmOptions }} + {{ $path }}: | +{{ $config | indent 4 -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/elasticsearch/templates/index_configmap.yaml b/elasticsearch/templates/index_configmap.yaml new file mode 100644 index 0000000..03b1f35 --- /dev/null +++ b/elasticsearch/templates/index_configmap.yaml @@ -0,0 +1,265 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: index-template-1 +data: + chat_v1_idx.json: | + { + "settings": { + "index": { + "number_of_shards": 3, + "number_of_replicas": 1, + "max_ngram_diff": 2 + }, + "analysis": { + "analyzer": { + "ngram_analyzer": { + "type": "custom", + "tokenizer": "ngram_tokenizer", + "filter": [ + "lowercase" + ] + }, + "standard_search_analyzer_lowercase": { + "type": "custom", + "tokenizer": "standard", + "filter": [ + "lowercase" + ] + } + }, + "tokenizer": { + "ngram_tokenizer": { + "type": "ngram", + "min_gram": 3, + "max_gram": 5, + "token_chars": [] + } + }, + "normalizer": { + "lowercase_normalizer": { + "type": "custom", + "filter": [ + "lowercase" + ] + } + } + } + }, + "mappings": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "type": "keyword", + "normalizer": "lowercase_normalizer" + }, + "name_ngram": { + "type": "text", + "analyzer": "ngram_analyzer", + "search_analyzer": "ngram_analyzer", + "index_options": "offsets", + "term_vector": "with_positions_offsets" + }, + "description": { + "type": "text", + "analyzer": "standard", + "search_analyzer": "standard_search_analyzer_lowercase", + "index_options": "offsets", + "term_vector": "with_positions_offsets" + }, + "_class": { + "type": "text", + "fields": { + "keyword": { + "ignore_above": 256.0, + "type": "keyword" + } + } + } + } + } + } + message_v1_idx.json: | + { + "settings": { + "index": { + "number_of_shards": "3", + "number_of_replicas": "1" + }, + "analysis": { + "analyzer": { + "edge_ngram_index_analyzer": { + "tokenizer": "edge_ngram_index_tokenizer", + "filter": [ + "lowercase", + "apostrophe", + "classic" + ] + }, + "message_search_analyzer": { + "tokenizer": "standard" + } + }, + "tokenizer": { + "edge_ngram_index_tokenizer": { + "type": "edge_ngram", + "min_gram": 1, + "max_gram": 20, + "token_chars": [ + "letter", + "digit" + ] + } + } + } + }, + "mappings": { + "properties": { + "chatId": { + "type": "long" + }, + "messageId": { + "type": "long" + }, + "serverTime": { + "type": "long" + }, + "_class": { + "type": "text", + "fields": { + "keyword": { + "ignore_above": 256.0, + "type": "keyword" + } + } + }, + "id": { + "type": "keyword" + }, + "text": { + "type": "text", + "analyzer": "edge_ngram_index_analyzer", + "search_analyzer": "message_search_analyzer", + "index_options": "offsets", + "term_vector": "with_positions_offsets" + } + } + } + } + user_v1_idx.json: | + { + "settings": { + "index": { + "number_of_shards": 3, + "number_of_replicas": 1, + "max_ngram_diff": 2 + }, + "analysis": { + "analyzer": { + "ngram_analyzer": { + "type": "custom", + "tokenizer": "ngram_tokenizer", + "filter": [ + "lowercase" + ] + }, + "standard_search_analyzer_lowercase": { + "type": "custom", + "tokenizer": "standard", + "filter": [ + "lowercase" + ] + } + }, + "tokenizer": { + "ngram_tokenizer": { + "type": "ngram", + "min_gram": 3, + "max_gram": 5, + "token_chars": [] + } + }, + "normalizer": { + "lowercase_normalizer": { + "type": "custom", + "filter": [ + "lowercase" + ] + } + } + } + }, + "mappings": { + "properties": { + "id": { + "type": "long" + }, + "username": { + "type": "keyword", + "normalizer": "lowercase_normalizer" + }, + "username_ngram": { + "type": "text", + "analyzer": "ngram_analyzer", + "search_analyzer": "ngram_analyzer", + "index_options": "offsets", + "term_vector": "with_positions_offsets" + }, + "nickname": { + "type": "keyword", + "normalizer": "lowercase_normalizer" + }, + "nickname_ngram": { + "type": "text", + "analyzer": "ngram_analyzer", + "search_analyzer": "ngram_analyzer", + "index_options": "offsets", + "term_vector": "with_positions_offsets" + }, + "phone": { + "type": "keyword", + "normalizer": "lowercase_normalizer" + }, + "phone_ngram": { + "type": "text", + "analyzer": "ngram_analyzer", + "search_analyzer": "ngram_analyzer", + "index_options": "offsets", + "term_vector": "with_positions_offsets" + }, + "email": { + "type": "keyword", + "normalizer": "lowercase_normalizer" + }, + "email_ngram": { + "type": "text", + "analyzer": "ngram_analyzer", + "search_analyzer": "ngram_analyzer", + "index_options": "offsets", + "term_vector": "with_positions_offsets" + }, + "job_title": { + "type": "keyword", + "normalizer": "lowercase_normalizer" + }, + "job_title_ngram": { + "type": "text", + "analyzer": "ngram_analyzer", + "search_analyzer": "ngram_analyzer", + "index_options": "offsets", + "term_vector": "with_positions_offsets" + }, + "_class": { + "type": "text", + "fields": { + "keyword": { + "ignore_above": 256.0, + "type": "keyword" + } + } + } + } + } + } \ No newline at end of file diff --git a/elasticsearch/templates/ingress.yaml b/elasticsearch/templates/ingress.yaml new file mode 100644 index 0000000..e60cebf --- /dev/null +++ b/elasticsearch/templates/ingress.yaml @@ -0,0 +1,64 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "elasticsearch.uname" . -}} +{{- $httpPort := .Values.httpPort -}} +{{- $pathtype := .Values.ingress.pathtype -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + app: {{ .Chart.Name }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className | quote }} + {{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- if .ingressPath }} + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- else }} +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end }} +{{- end}} + rules: + {{- range .Values.ingress.hosts }} + {{- if $ingressPath }} + - host: {{ . }} + http: + paths: + - path: {{ $ingressPath }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ $fullName }} + port: + number: {{ $httpPort }} + {{- else }} + - host: {{ .host }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ $pathtype }} + backend: + service: + name: {{ $fullName }} + port: + number: {{ .servicePort | default $httpPort }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} diff --git a/elasticsearch/templates/networkpolicy.yaml b/elasticsearch/templates/networkpolicy.yaml new file mode 100644 index 0000000..62bb1bd --- /dev/null +++ b/elasticsearch/templates/networkpolicy.yaml @@ -0,0 +1,61 @@ +{{- if (or .Values.networkPolicy.http.enabled .Values.networkPolicy.transport.enabled) }} +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + name: {{ template "elasticsearch.uname" . }} + labels: + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}" + app: "{{ template "elasticsearch.uname" . }}" +spec: + podSelector: + matchLabels: + app: "{{ template "elasticsearch.uname" . }}" + ingress: # Allow inbound connections + +{{- if .Values.networkPolicy.http.enabled }} + # For HTTP access + - ports: + - port: {{ .Values.httpPort }} + from: + # From authorized Pods (having the correct label) + - podSelector: + matchLabels: + {{ template "elasticsearch.uname" . }}-http-client: "true" +{{- with .Values.networkPolicy.http.explicitNamespacesSelector }} + # From authorized namespaces + namespaceSelector: +{{ toYaml . | indent 12 }} +{{- end }} +{{- with .Values.networkPolicy.http.additionalRules }} + # Or from custom additional rules +{{ toYaml . | indent 8 }} +{{- end }} +{{- end }} + +{{- if .Values.networkPolicy.transport.enabled }} + # For transport access + - ports: + - port: {{ .Values.transportPort }} + from: + # From authorized Pods (having the correct label) + - podSelector: + matchLabels: + {{ template "elasticsearch.uname" . }}-transport-client: "true" +{{- with .Values.networkPolicy.transport.explicitNamespacesSelector }} + # From authorized namespaces + namespaceSelector: +{{ toYaml . | indent 12 }} +{{- end }} +{{- with .Values.networkPolicy.transport.additionalRules }} + # Or from custom additional rules +{{ toYaml . | indent 8 }} +{{- end }} + # Or from other ElasticSearch Pods + - podSelector: + matchLabels: + app: "{{ template "elasticsearch.uname" . }}" +{{- end }} + +{{- end }} diff --git a/elasticsearch/templates/poddisruptionbudget.yaml b/elasticsearch/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..6d0bdf3 --- /dev/null +++ b/elasticsearch/templates/poddisruptionbudget.yaml @@ -0,0 +1,15 @@ +{{- if .Values.maxUnavailable }} +{{- if .Capabilities.APIVersions.Has "policy/v1" -}} +apiVersion: policy/v1 +{{- else}} +apiVersion: policy/v1beta1 +{{- end }} +kind: PodDisruptionBudget +metadata: + name: "{{ template "elasticsearch.uname" . }}-pdb" +spec: + maxUnavailable: {{ .Values.maxUnavailable }} + selector: + matchLabels: + app: "{{ template "elasticsearch.uname" . }}" +{{- end }} diff --git a/elasticsearch/templates/podsecuritypolicy.yaml b/elasticsearch/templates/podsecuritypolicy.yaml new file mode 100644 index 0000000..d8b3545 --- /dev/null +++ b/elasticsearch/templates/podsecuritypolicy.yaml @@ -0,0 +1,14 @@ +{{- if .Values.podSecurityPolicy.create -}} +{{- $fullName := include "elasticsearch.uname" . -}} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ default $fullName .Values.podSecurityPolicy.name | quote }} + labels: + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + app: {{ $fullName | quote }} +spec: +{{ toYaml .Values.podSecurityPolicy.spec | indent 2 }} +{{- end -}} diff --git a/elasticsearch/templates/role.yaml b/elasticsearch/templates/role.yaml new file mode 100644 index 0000000..d3a7ee3 --- /dev/null +++ b/elasticsearch/templates/role.yaml @@ -0,0 +1,25 @@ +{{- if .Values.rbac.create -}} +{{- $fullName := include "elasticsearch.uname" . -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ $fullName | quote }} + labels: + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + app: {{ $fullName | quote }} +rules: + - apiGroups: + - extensions + resources: + - podsecuritypolicies + resourceNames: + {{- if eq .Values.podSecurityPolicy.name "" }} + - {{ $fullName | quote }} + {{- else }} + - {{ .Values.podSecurityPolicy.name | quote }} + {{- end }} + verbs: + - use +{{- end -}} diff --git a/elasticsearch/templates/rolebinding.yaml b/elasticsearch/templates/rolebinding.yaml new file mode 100644 index 0000000..e0ecced --- /dev/null +++ b/elasticsearch/templates/rolebinding.yaml @@ -0,0 +1,20 @@ +{{- if .Values.rbac.create -}} +{{- $fullName := include "elasticsearch.uname" . -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ $fullName | quote }} + labels: + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + app: {{ $fullName | quote }} +subjects: + - kind: ServiceAccount + name: "{{ template "elasticsearch.serviceAccount" . }}" + namespace: {{ .Release.Namespace | quote }} +roleRef: + kind: Role + name: {{ $fullName | quote }} + apiGroup: rbac.authorization.k8s.io +{{- end -}} diff --git a/elasticsearch/templates/secret-cert.yaml b/elasticsearch/templates/secret-cert.yaml new file mode 100644 index 0000000..97d8dec --- /dev/null +++ b/elasticsearch/templates/secret-cert.yaml @@ -0,0 +1,14 @@ +{{- if .Values.createCert }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/tls +metadata: + name: {{ template "elasticsearch.uname" . }}-certs + labels: + app: {{ template "elasticsearch.uname" . }} + chart: "{{ .Chart.Name }}" + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +data: +{{ ( include "elasticsearch.gen-certs" . ) | indent 2 }} +{{- end }} diff --git a/elasticsearch/templates/secret.yaml b/elasticsearch/templates/secret.yaml new file mode 100644 index 0000000..cbdcbba --- /dev/null +++ b/elasticsearch/templates/secret.yaml @@ -0,0 +1,23 @@ +{{- if .Values.secret.enabled -}} +{{- $passwordValue := (randAlphaNum 16) | b64enc | quote }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "elasticsearch.uname" . }}-credentials + labels: + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}" + app: "{{ template "elasticsearch.uname" . }}" + {{- range $key, $value := .Values.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} +type: Opaque +data: + username: {{ "elastic" | b64enc }} + {{- if .Values.secret.password }} + password: {{ .Values.secret.password | b64enc }} + {{- else }} + password: {{ $passwordValue }} + {{- end }} +{{- end }} diff --git a/elasticsearch/templates/service.yaml b/elasticsearch/templates/service.yaml new file mode 100644 index 0000000..5fe52eb --- /dev/null +++ b/elasticsearch/templates/service.yaml @@ -0,0 +1,78 @@ +{{- if .Values.service.enabled -}} +--- +kind: Service +apiVersion: v1 +metadata: +{{- if eq .Values.nodeGroup "master" }} + name: {{ template "elasticsearch.masterService" . }} +{{- else }} + name: {{ template "elasticsearch.uname" . }} +{{- end }} + labels: + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}" + app: "{{ template "elasticsearch.uname" . }}" +{{- if .Values.service.labels }} +{{ toYaml .Values.service.labels | indent 4}} +{{- end }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +spec: + type: {{ .Values.service.type }} + selector: + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}" + app: "{{ template "elasticsearch.uname" . }}" + publishNotReadyAddresses: {{ .Values.service.publishNotReadyAddresses }} + ports: + - name: {{ .Values.service.httpPortName | default "http" }} + protocol: TCP + port: {{ .Values.httpPort }} +{{- if .Values.service.nodePort }} + nodePort: {{ .Values.service.nodePort }} +{{- end }} + - name: {{ .Values.service.transportPortName | default "transport" }} + protocol: TCP + port: {{ .Values.transportPort }} +{{- if .Values.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} +{{- end }} +{{- with .Values.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{ toYaml . | indent 4 }} +{{- end }} +{{- if .Values.service.externalTrafficPolicy }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }} +{{- end }} +{{- end }} +--- +kind: Service +apiVersion: v1 +metadata: +{{- if eq .Values.nodeGroup "master" }} + name: {{ template "elasticsearch.masterService" . }}-headless +{{- else }} + name: {{ template "elasticsearch.uname" . }}-headless +{{- end }} + labels: + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}" + app: "{{ template "elasticsearch.uname" . }}" +{{- if .Values.service.labelsHeadless }} +{{ toYaml .Values.service.labelsHeadless | indent 4 }} +{{- end }} + annotations: + service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" +spec: + clusterIP: None # This is needed for statefulset hostnames like elasticsearch-0 to resolve + # Create endpoints also if the related pod isn't ready + publishNotReadyAddresses: true + selector: + app: "{{ template "elasticsearch.uname" . }}" + ports: + - name: {{ .Values.service.httpPortName | default "http" }} + port: {{ .Values.httpPort }} + - name: {{ .Values.service.transportPortName | default "transport" }} + port: {{ .Values.transportPort }} diff --git a/elasticsearch/templates/serviceaccount.yaml b/elasticsearch/templates/serviceaccount.yaml new file mode 100644 index 0000000..a7ef847 --- /dev/null +++ b/elasticsearch/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.rbac.create -}} +{{- $fullName := include "elasticsearch.uname" . -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "{{ template "elasticsearch.serviceAccount" . }}" + annotations: + {{- with .Values.rbac.serviceAccountAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + app: {{ $fullName | quote }} +{{- end -}} diff --git a/elasticsearch/templates/statefulset.yaml b/elasticsearch/templates/statefulset.yaml new file mode 100644 index 0000000..64fd423 --- /dev/null +++ b/elasticsearch/templates/statefulset.yaml @@ -0,0 +1,427 @@ +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ template "elasticsearch.uname" . }} + labels: + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}" + app: "{{ template "elasticsearch.uname" . }}" + {{- range $key, $value := .Values.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + annotations: + esMajorVersion: "{{ include "elasticsearch.esMajorVersion" . }}" +spec: + serviceName: {{ template "elasticsearch.uname" . }}-headless + selector: + matchLabels: + app: "{{ template "elasticsearch.uname" . }}" + replicas: {{ .Values.replicas }} + podManagementPolicy: {{ .Values.podManagementPolicy }} + updateStrategy: + type: {{ .Values.updateStrategy }} + {{- if .Values.persistence.enabled }} + volumeClaimTemplates: + - metadata: + name: {{ template "elasticsearch.uname" . }} + {{- if .Values.persistence.labels.enabled }} + labels: + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}" + app: "{{ template "elasticsearch.uname" . }}" + {{- range $key, $value := .Values.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- end }} + {{- with .Values.persistence.annotations }} + annotations: +{{ toYaml . | indent 8 }} + {{- end }} + spec: +{{ toYaml .Values.volumeClaimTemplate | indent 6 }} + {{- end }} + template: + metadata: + name: "{{ template "elasticsearch.uname" . }}" + labels: + release: {{ .Release.Name | quote }} + chart: "{{ .Chart.Name }}" + app: "{{ template "elasticsearch.uname" . }}" + {{- range $key, $value := .Values.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + annotations: + {{- range $key, $value := .Values.podAnnotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{/* This forces a restart if the configmap has changed */}} + {{- if or .Values.esConfig .Values.esJvmOptions }} + configchecksum: {{ include (print .Template.BasePath "/configmap.yaml") . | sha256sum | trunc 63 }} + {{- end }} + spec: + {{- if .Values.schedulerName }} + schedulerName: "{{ .Values.schedulerName }}" + {{- end }} + securityContext: +{{ toYaml .Values.podSecurityContext | indent 8 }} + {{- if .Values.fsGroup }} + fsGroup: {{ .Values.fsGroup }} # Deprecated value, please use .Values.podSecurityContext.fsGroup + {{- end }} + {{- if or .Values.rbac.create .Values.rbac.serviceAccountName }} + serviceAccountName: "{{ template "elasticsearch.serviceAccount" . }}" + {{- end }} + automountServiceAccountToken: {{ .Values.rbac.automountToken }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 6 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if or (eq .Values.antiAffinity "hard") (eq .Values.antiAffinity "soft") .Values.nodeAffinity }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName }} + {{- end }} + affinity: + {{- end }} + {{- if eq .Values.antiAffinity "hard" }} + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app + operator: In + values: + - "{{ template "elasticsearch.uname" .}}" + topologyKey: {{ .Values.antiAffinityTopologyKey }} + {{- else if eq .Values.antiAffinity "soft" }} + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + podAffinityTerm: + topologyKey: {{ .Values.antiAffinityTopologyKey }} + labelSelector: + matchExpressions: + - key: app + operator: In + values: + - "{{ template "elasticsearch.uname" . }}" + {{- end }} + {{- with .Values.nodeAffinity }} + nodeAffinity: +{{ toYaml . | indent 10 }} + {{- end }} + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriod }} + volumes: + {{- range .Values.secretMounts }} + - name: {{ .name }} + secret: + secretName: {{ .secretName }} + {{- if .defaultMode }} + defaultMode: {{ .defaultMode }} + {{- end }} + {{- end }} + {{- if .Values.esConfig }} + - name: esconfig + configMap: + name: {{ template "elasticsearch.uname" . }}-config + {{- end }} + {{- if .Values.esJvmOptions }} + - name: esjvmoptions + configMap: + name: {{ template "elasticsearch.uname" . }}-jvm-options + {{- end }} + {{- if .Values.createCert }} + - name: elasticsearch-certs + secret: + secretName: {{ template "elasticsearch.uname" . }}-certs + {{- end }} +{{- if .Values.keystore }} + - name: keystore + emptyDir: {} + {{- range .Values.keystore }} + - name: keystore-{{ .secretName }} + secret: {{ toYaml . | nindent 12 }} + {{- end }} +{{ end }} + {{- if .Values.extraVolumes }} + # Currently some extra blocks accept strings + # to continue with backwards compatibility this is being kept + # whilst also allowing for yaml to be specified too. + {{- if eq "string" (printf "%T" .Values.extraVolumes) }} +{{ tpl .Values.extraVolumes . | indent 8 }} + {{- else }} +{{ toYaml .Values.extraVolumes | indent 8 }} + {{- end }} + {{- end }} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: +{{ toYaml .Values.imagePullSecrets | indent 8 }} + {{- end }} + enableServiceLinks: {{ .Values.enableServiceLinks }} + {{- if .Values.hostAliases }} + hostAliases: {{ toYaml .Values.hostAliases | nindent 8 }} + {{- end }} + {{- if or (.Values.extraInitContainers) (.Values.sysctlInitContainer.enabled) (.Values.keystore) }} + initContainers: + {{- if .Values.sysctlInitContainer.enabled }} + - name: configure-sysctl + securityContext: + runAsUser: 0 + privileged: true + image: "{{ .Values.image }}:{{ .Values.imageTag }}" + imagePullPolicy: "{{ .Values.imagePullPolicy }}" + command: ["sysctl", "-w", "vm.max_map_count={{ .Values.sysctlVmMaxMapCount}}"] + resources: +{{ toYaml .Values.initResources | indent 10 }} + {{- end }} +{{ if .Values.keystore }} + - name: keystore + securityContext: +{{ toYaml .Values.securityContext | indent 10 }} + image: "{{ .Values.image }}:{{ .Values.imageTag }}" + imagePullPolicy: "{{ .Values.imagePullPolicy }}" + command: + - bash + - -c + - | + set -euo pipefail + + elasticsearch-keystore create + + for i in /tmp/keystoreSecrets/*/*; do + key=$(basename $i) + echo "Adding file $i to keystore key $key" + elasticsearch-keystore add-file "$key" "$i" + done + + # Add the bootstrap password since otherwise the Elasticsearch entrypoint tries to do this on startup + if [ ! -z ${ELASTIC_PASSWORD+x} ]; then + echo 'Adding env $ELASTIC_PASSWORD to keystore as key bootstrap.password' + echo "$ELASTIC_PASSWORD" | elasticsearch-keystore add -x bootstrap.password + fi + + cp -a /usr/share/elasticsearch/config/elasticsearch.keystore /tmp/keystore/ + env: {{ toYaml .Values.extraEnvs | nindent 10 }} + envFrom: {{ toYaml .Values.envFrom | nindent 10 }} + resources: {{ toYaml .Values.initResources | nindent 10 }} + volumeMounts: + - name: keystore + mountPath: /tmp/keystore + {{- range .Values.keystore }} + - name: keystore-{{ .secretName }} + mountPath: /tmp/keystoreSecrets/{{ .secretName }} + {{- end }} +{{ end }} + {{- if .Values.extraInitContainers }} + # Currently some extra blocks accept strings + # to continue with backwards compatibility this is being kept + # whilst also allowing for yaml to be specified too. + {{- if eq "string" (printf "%T" .Values.extraInitContainers) }} +{{ tpl .Values.extraInitContainers . | indent 6 }} + {{- else }} +{{ toYaml .Values.extraInitContainers | indent 6 }} + {{- end }} + {{- end }} + {{- end }} + containers: + - name: "{{ template "elasticsearch.name" . }}" + securityContext: +{{ toYaml .Values.securityContext | indent 10 }} + image: "{{ .Values.image }}:{{ .Values.imageTag }}" + imagePullPolicy: "{{ .Values.imagePullPolicy }}" + readinessProbe: + exec: + command: + - bash + - -c + - | + set -e + + # Exit if ELASTIC_PASSWORD in unset + if [ -z "${ELASTIC_PASSWORD}" ]; then + echo "ELASTIC_PASSWORD variable is missing, exiting" + exit 1 + fi + + # If the node is starting up wait for the cluster to be ready (request params: "{{ .Values.clusterHealthCheckParams }}" ) + # Once it has started only check that the node itself is responding + START_FILE=/tmp/.es_start_file + + # Disable nss cache to avoid filling dentry cache when calling curl + # This is required with Elasticsearch Docker using nss < 3.52 + export NSS_SDB_USE_CACHE=no + + http () { + local path="${1}" + local args="${2}" + set -- -XGET -s + + if [ "$args" != "" ]; then + set -- "$@" $args + fi + + set -- "$@" -u "elastic:${ELASTIC_PASSWORD}" + + curl --output /dev/null -k "$@" "{{ .Values.protocol }}://127.0.0.1:{{ .Values.httpPort }}${path}" + } + + if [ -f "${START_FILE}" ]; then + echo 'Elasticsearch is already running, lets check the node is healthy' + HTTP_CODE=$(http "/" "-w %{http_code}") + RC=$? + if [[ ${RC} -ne 0 ]]; then + echo "curl --output /dev/null -k -XGET -s -w '%{http_code}' \${BASIC_AUTH} {{ .Values.protocol }}://127.0.0.1:{{ .Values.httpPort }}/ failed with RC ${RC}" + exit ${RC} + fi + # ready if HTTP code 200, 503 is tolerable if ES version is 6.x + if [[ ${HTTP_CODE} == "200" ]]; then + exit 0 + elif [[ ${HTTP_CODE} == "503" && "{{ include "elasticsearch.esMajorVersion" . }}" == "6" ]]; then + exit 0 + else + echo "curl --output /dev/null -k -XGET -s -w '%{http_code}' \${BASIC_AUTH} {{ .Values.protocol }}://127.0.0.1:{{ .Values.httpPort }}/ failed with HTTP code ${HTTP_CODE}" + exit 1 + fi + + else + echo 'Waiting for elasticsearch cluster to become ready (request params: "{{ .Values.clusterHealthCheckParams }}" )' + if http "/_cluster/health?{{ .Values.clusterHealthCheckParams }}" "--fail" ; then + touch ${START_FILE} + exit 0 + else + echo 'Cluster is not yet ready (request params: "{{ .Values.clusterHealthCheckParams }}" )' + exit 1 + fi + fi +{{ toYaml .Values.readinessProbe | indent 10 }} + ports: + - name: http + containerPort: {{ .Values.httpPort }} + - name: transport + containerPort: {{ .Values.transportPort }} + resources: +{{ toYaml .Values.resources | indent 10 }} + env: + - name: node.name + valueFrom: + fieldRef: + fieldPath: metadata.name + {{- if has "master" .Values.roles }} + - name: cluster.initial_master_nodes + value: "{{ template "elasticsearch.endpoints" . }}" + {{- end }} + {{- if gt (len (include "elasticsearch.roles" .)) 0 }} + - name: node.roles + value: "{{ template "elasticsearch.roles" . }}" + {{- end }} + {{- if lt (int (include "elasticsearch.esMajorVersion" .)) 7 }} + - name: discovery.zen.ping.unicast.hosts + value: "{{ template "elasticsearch.masterService" . }}-headless" + {{- else }} + - name: discovery.seed_hosts + value: "{{ template "elasticsearch.masterService" . }}-headless" + {{- end }} + - name: cluster.name + value: "{{ .Values.clusterName }}" + - name: network.host + value: "{{ .Values.networkHost }}" + {{- if .Values.secret.enabled }} + - name: ELASTIC_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "elasticsearch.uname" . }}-credentials + key: password + {{- end }} + {{- if .Values.esJavaOpts }} + - name: ES_JAVA_OPTS + value: "{{ .Values.esJavaOpts }}" + {{- end }} + {{- if .Values.createCert }} + - name: xpack.security.enabled + value: "true" + - name: xpack.security.transport.ssl.enabled + value: "true" + - name: xpack.security.http.ssl.enabled + value: "true" + - name: xpack.security.transport.ssl.verification_mode + value: "certificate" + - name: xpack.security.transport.ssl.key + value: "/usr/share/elasticsearch/config/certs/tls.key" + - name: xpack.security.transport.ssl.certificate + value: "/usr/share/elasticsearch/config/certs/tls.crt" + - name: xpack.security.transport.ssl.certificate_authorities + value: "/usr/share/elasticsearch/config/certs/ca.crt" + - name: xpack.security.http.ssl.key + value: "/usr/share/elasticsearch/config/certs/tls.key" + - name: xpack.security.http.ssl.certificate + value: "/usr/share/elasticsearch/config/certs/tls.crt" + - name: xpack.security.http.ssl.certificate_authorities + value: "/usr/share/elasticsearch/config/certs/ca.crt" + {{- end }} +{{- if .Values.extraEnvs }} +{{ toYaml .Values.extraEnvs | indent 10 }} +{{- end }} +{{- if .Values.envFrom }} + envFrom: +{{ toYaml .Values.envFrom | indent 10 }} +{{- end }} + volumeMounts: + {{- if .Values.persistence.enabled }} + - name: "{{ template "elasticsearch.uname" . }}" + mountPath: /usr/share/elasticsearch/data + {{- end }} + {{- if .Values.createCert }} + - name: elasticsearch-certs + mountPath: /usr/share/elasticsearch/config/certs + readOnly: true + {{- end }} +{{ if .Values.keystore }} + - name: keystore + mountPath: /usr/share/elasticsearch/config/elasticsearch.keystore + subPath: elasticsearch.keystore +{{ end }} + {{- range .Values.secretMounts }} + - name: {{ .name }} + mountPath: {{ .path }} + {{- if .subPath }} + subPath: {{ .subPath }} + {{- end }} + {{- end }} + {{- range $path, $config := .Values.esConfig }} + - name: esconfig + mountPath: /usr/share/elasticsearch/config/{{ $path }} + subPath: {{ $path }} + {{- end -}} + {{- range $path, $config := .Values.esJvmOptions }} + - name: esjvmoptions + mountPath: /usr/share/elasticsearch/config/jvm.options.d/{{ $path }} + subPath: {{ $path }} + {{- end -}} + {{- if .Values.extraVolumeMounts }} + # Currently some extra blocks accept strings + # to continue with backwards compatibility this is being kept + # whilst also allowing for yaml to be specified too. + {{- if eq "string" (printf "%T" .Values.extraVolumeMounts) }} +{{ tpl .Values.extraVolumeMounts . | indent 10 }} + {{- else }} +{{ toYaml .Values.extraVolumeMounts | indent 10 }} + {{- end }} + {{- end }} +{{- if .Values.lifecycle }} + lifecycle: +{{ toYaml .Values.lifecycle | indent 10 }} +{{- end }} + {{- if .Values.extraContainers }} + # Currently some extra blocks accept strings + # to continue with backwards compatibility this is being kept + # whilst also allowing for yaml to be specified too. + {{- if eq "string" (printf "%T" .Values.extraContainers) }} +{{ tpl .Values.extraContainers . | indent 6 }} + {{- else }} +{{ toYaml .Values.extraContainers | indent 6 }} + {{- end }} + {{- end }} diff --git a/elasticsearch/templates/test/test-elasticsearch-health.yaml b/elasticsearch/templates/test/test-elasticsearch-health.yaml new file mode 100644 index 0000000..d0890fb --- /dev/null +++ b/elasticsearch/templates/test/test-elasticsearch-health.yaml @@ -0,0 +1,50 @@ +{{- if .Values.tests.enabled -}} +--- +apiVersion: v1 +kind: Pod +metadata: +{{- if .Values.healthNameOverride }} + name: {{ .Values.healthNameOverride | quote }} +{{- else }} + name: "{{ .Release.Name }}-{{ randAlpha 5 | lower }}-test" +{{- end }} + annotations: + "helm.sh/hook": test + "helm.sh/hook-delete-policy": hook-succeeded +spec: + securityContext: +{{ toYaml .Values.podSecurityContext | indent 4 }} + containers: +{{- if .Values.healthNameOverride }} + - name: {{ .Values.healthNameOverride | quote }} +{{- else }} + - name: "{{ .Release.Name }}-{{ randAlpha 5 | lower }}-test" +{{- end }} + env: + - name: ELASTIC_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "elasticsearch.uname" . }}-credentials + key: password + image: "{{ .Values.image }}:{{ .Values.imageTag }}" + imagePullPolicy: "{{ .Values.imagePullPolicy }}" + command: + - "sh" + - "-c" + - | + #!/usr/bin/env bash -e + curl -XGET --fail --cacert /usr/share/elasticsearch/config/certs/tls.crt -u "elastic:${ELASTIC_PASSWORD}" https://'{{ template "elasticsearch.uname" . }}:{{ .Values.httpPort }}/_cluster/health?{{ .Values.clusterHealthCheckParams }}' + volumeMounts: + - name: elasticsearch-certs + mountPath: /usr/share/elasticsearch/config/certs + readOnly: true + {{- if .Values.imagePullSecrets }} + imagePullSecrets: +{{ toYaml .Values.imagePullSecrets | indent 4 }} + {{- end }} + restartPolicy: Never + volumes: + - name: elasticsearch-certs + secret: + secretName: {{ template "elasticsearch.uname" . }}-certs +{{- end -}} diff --git a/elasticsearch/values.yaml b/elasticsearch/values.yaml new file mode 100644 index 0000000..1f31632 --- /dev/null +++ b/elasticsearch/values.yaml @@ -0,0 +1,682 @@ +--- +clusterName: "elasticsearch" +nodeGroup: "master" + +# The service that non master groups will try to connect to when joining the cluster +# This should be set to clusterName + "-" + nodeGroup for your master group +masterService: "" + +# Elasticsearch roles that will be applied to this nodeGroup +# These will be set as environment variables. E.g. node.roles=master +# https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html#node-roles +roles: + - master + - data + - data_content + - data_hot + - data_warm + - data_cold + - ingest + - ml + - remote_cluster_client + - transform + +replicas: 3 +minimumMasterNodes: 2 + +esMajorVersion: "" + +# Allows you to add any config files in /usr/share/elasticsearch/config/ +# such as elasticsearch.yml and log4j2.properties +esConfig: {} +# elasticsearch.yml: | +# key: +# nestedkey: value +# log4j2.properties: | +# key = value + +createCert: true + +esJvmOptions: {} +# processors.options: | +# -XX:ActiveProcessorCount=3 + +# Extra environment variables to append to this nodeGroup +# This will be appended to the current 'env:' key. You can use any of the kubernetes env +# syntax here +extraEnvs: + - name: ES_USERNAME + valueFrom: + secretKeyRef: + name: elasticsearch-master-credentials + key: username + - name: ES_PASSWORD + valueFrom: + secretKeyRef: + name: elasticsearch-master-credentials + key: password + - name: CA_CERT + value: "/usr/share/elasticsearch/config/http-certs/ca.crt" + - name: ES_URL + value: "https://elasticsearch-master:9200" + - name: TEMPLATE_PATH_1 + value: "/usr/share/elasticsearch/templates/chat_v1_idx.json" + - name: TEMPLATE_PATH_2 + value: "/usr/share/elasticsearch/templates/message_v1_idx.json" + - name: TEMPLATE_PATH_3 + value: "/usr/share/elasticsearch/templates/user_v1_idx.json" + - name: MAX_RETRIES + value: "30" + +# Allows you to load environment variables from kubernetes secret or config map +envFrom: [] +# - secretRef: +# name: env-secret +# - configMapRef: +# name: config-map + +# Disable it to use your own elastic-credential Secret. +secret: + enabled: true + password: "" # generated randomly if not defined + +# A list of secrets and their paths to mount inside the pod +# This is useful for mounting certificates for security and for mounting +# the X-Pack license +secretMounts: [] +# - name: elastic-certificates +# secretName: elastic-certificates +# path: /usr/share/elasticsearch/config/certs +# defaultMode: 0755 + +hostAliases: [] +#- ip: "127.0.0.1" +# hostnames: +# - "foo.local" +# - "bar.local" + +image: "docker.io/library/elasticsearch" +imageTag: "8.5.1" +imagePullPolicy: "IfNotPresent" + +podAnnotations: {} +# iam.amazonaws.com/role: es-cluster + +# additionals labels +labels: {} + +esJavaOpts: "" # example: "-Xmx1g -Xms1g" + +resources: + requests: + cpu: "1000m" + memory: "2Gi" + limits: + cpu: "1000m" + memory: "2Gi" + +initResources: {} +# limits: +# cpu: "25m" +# # memory: "128Mi" +# requests: +# cpu: "25m" +# memory: "128Mi" + +networkHost: "0.0.0.0" + +volumeClaimTemplate: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 30Gi + +rbac: + create: false + serviceAccountAnnotations: {} + serviceAccountName: "" + automountToken: true + +podSecurityPolicy: + create: false + name: "" + spec: + privileged: true + fsGroup: + rule: RunAsAny + runAsUser: + rule: RunAsAny + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + volumes: + - secret + - configMap + - persistentVolumeClaim + - emptyDir + +persistence: + enabled: true + labels: + # Add default labels for the volumeClaimTemplate of the StatefulSet + enabled: false + annotations: {} + +extraVolumeMounts: + - name: index-template + mountPath: /usr/share/elasticsearch/templates + readOnly: true + - name: http-cert + mountPath: /usr/share/elasticsearch/config/http-certs + readOnly: true + +extraContainers: [] +# - name: do-something +# image: busybox +# command: ['do', 'something'] + + +extraInitContainers: [] +# - name: es-index-init +# image: alpine/curl:latest +# command: ['/bin/sh', '-c'] +# args: +# - | +# ES_HOST="elasticsearch-master" # Match your ES service name +# ES_PORT="9200" +# ELASTIC_PASSWORD=$(cat /etc/elasticsearch-password/password) +# curl -u "elastic:${ELASTIC_PASSWORD}" -X PUT "http://${ES_HOST}:${ES_PORT}/chat_v1_idx?pretty" -H 'Content-Type: application/json' -d' +# { +# "settings": { +# "index": { +# "number_of_shards": 3, +# "number_of_replicas": 1, +# "max_ngram_diff": 2 +# }, +# "analysis": { +# "analyzer": { +# "ngram_analyzer": { +# "type": "custom", +# "tokenizer": "ngram_tokenizer", +# "filter": [ +# "lowercase" +# ] +# }, +# "standard_search_analyzer_lowercase": { +# "type": "custom", +# "tokenizer": "standard", +# "filter": [ +# "lowercase" +# ] +# } +# }, +# "tokenizer": { +# "ngram_tokenizer": { +# "type": "ngram", +# "min_gram": 3, +# "max_gram": 5, +# "token_chars": [] +# } +# }, +# "normalizer": { +# "lowercase_normalizer": { +# "type": "custom", +# "filter": [ +# "lowercase" +# ] +# } +# } +# } +# }, +# "mappings": { +# "properties": { +# "id": { +# "type": "long" +# }, +# "name": { +# "type": "keyword", +# "normalizer": "lowercase_normalizer" +# }, +# "name_ngram": { +# "type": "text", +# "analyzer": "ngram_analyzer", +# "search_analyzer": "ngram_analyzer", +# "index_options": "offsets", +# "term_vector": "with_positions_offsets" +# }, +# "description": { +# "type": "text", +# "analyzer": "standard", +# "search_analyzer": "standard_search_analyzer_lowercase", +# "index_options": "offsets", +# "term_vector": "with_positions_offsets" +# }, +# "_class": { +# "type": "text", +# "fields": { +# "keyword": { +# "ignore_above": 256.0, +# "type": "keyword" +# } +# } +# } +# } +# } +# } +# curl -u "elastic:${ELASTIC_PASSWORD}" -X PUT "http://${ES_HOST}:${ES_PORT}/message_v1_idx?pretty" -H 'Content-Type: application/json' -d' +# { +# "settings": { +# "index": { +# "number_of_shards": "3", +# "number_of_replicas": "1" +# }, +# "analysis": { +# "analyzer": { +# "edge_ngram_index_analyzer": { +# "tokenizer": "edge_ngram_index_tokenizer", +# "filter": [ +# "lowercase", +# "apostrophe", +# "classic" +# ] +# }, +# "message_search_analyzer": { +# "tokenizer": "standard" +# } +# }, +# "tokenizer": { +# "edge_ngram_index_tokenizer": { +# "type": "edge_ngram", +# "min_gram": 1, +# "max_gram": 20, +# "token_chars": [ +# "letter", +# "digit" +# ] +# } +# } +# } +# }, +# "mappings": { +# "properties": { +# "chatId": { +# "type": "long" +# }, +# "messageId": { +# "type": "long" +# }, +# "serverTime": { +# "type": "long" +# }, +# "_class": { +# "type": "text", +# "fields": { +# "keyword": { +# "ignore_above": 256.0, +# "type": "keyword" +# } +# } +# }, +# "id": { +# "type": "keyword" +# }, +# "text": { +# "type": "text", +# "analyzer": "edge_ngram_index_analyzer", +# "search_analyzer": "message_search_analyzer", +# "index_options": "offsets", +# "term_vector": "with_positions_offsets" +# } +# } +# } +# } +# curl -u "elastic:${ELASTIC_PASSWORD}" -X PUT "http://${ES_HOST}:${ES_PORT}/user_v1_idx?pretty" -H 'Content-Type: application/json' -d' +# { +# "settings": { +# "index": { +# "number_of_shards": 3, +# "number_of_replicas": 1, +# "max_ngram_diff": 2 +# }, +# "analysis": { +# "analyzer": { +# "ngram_analyzer": { +# "type": "custom", +# "tokenizer": "ngram_tokenizer", +# "filter": [ +# "lowercase" +# ] +# }, +# "standard_search_analyzer_lowercase": { +# "type": "custom", +# "tokenizer": "standard", +# "filter": [ +# "lowercase" +# ] +# } +# }, +# "tokenizer": { +# "ngram_tokenizer": { +# "type": "ngram", +# "min_gram": 3, +# "max_gram": 5, +# "token_chars": [] +# } +# }, +# "normalizer": { +# "lowercase_normalizer": { +# "type": "custom", +# "filter": [ +# "lowercase" +# ] +# } +# } +# } +# }, +# "mappings": { +# "properties": { +# "id": { +# "type": "long" +# }, +# "username": { +# "type": "keyword", +# "normalizer": "lowercase_normalizer" +# }, +# "username_ngram": { +# "type": "text", +# "analyzer": "ngram_analyzer", +# "search_analyzer": "ngram_analyzer", +# "index_options": "offsets", +# "term_vector": "with_positions_offsets" +# }, +# "nickname": { +# "type": "keyword", +# "normalizer": "lowercase_normalizer" +# }, +# "nickname_ngram": { +# "type": "text", +# "analyzer": "ngram_analyzer", +# "search_analyzer": "ngram_analyzer", +# "index_options": "offsets", +# "term_vector": "with_positions_offsets" +# }, +# "phone": { +# "type": "keyword", +# "normalizer": "lowercase_normalizer" +# }, +# "phone_ngram": { +# "type": "text", +# "analyzer": "ngram_analyzer", +# "search_analyzer": "ngram_analyzer", +# "index_options": "offsets", +# "term_vector": "with_positions_offsets" +# }, +# "email": { +# "type": "keyword", +# "normalizer": "lowercase_normalizer" +# }, +# "email_ngram": { +# "type": "text", +# "analyzer": "ngram_analyzer", +# "search_analyzer": "ngram_analyzer", +# "index_options": "offsets", +# "term_vector": "with_positions_offsets" +# }, +# "job_title": { +# "type": "keyword", +# "normalizer": "lowercase_normalizer" +# }, +# "job_title_ngram": { +# "type": "text", +# "analyzer": "ngram_analyzer", +# "search_analyzer": "ngram_analyzer", +# "index_options": "offsets", +# "term_vector": "with_positions_offsets" +# }, +# "_class": { +# "type": "text", +# "fields": { +# "keyword": { +# "ignore_above": 256.0, +# "type": "keyword" +# } +# } +# } +# } +# } +# } +# volumeMounts: +# - name: elasticsearch-password +# mountPath: /etc/elasticsearch-password +# readOnly: true + +extraVolumes: + # Mount the JSON template + - name: index-template + configMap: + name: index-template-1 + - name: http-cert + secret: + secretName: elasticsearch-master-certs + + # (Secret volume is optional; we’ll inject via envFrom) +# This is the PriorityClass settings as defined in +# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass +priorityClassName: "" + +# By default this will make sure two pods don't end up on the same node +# Changing this to a region would allow you to spread pods across regions +antiAffinityTopologyKey: "kubernetes.io/hostname" + +# Hard means that by default pods will only be scheduled if there are enough nodes for them +# and that they will never end up on the same node. Setting this to soft will do this "best effort" +antiAffinity: "hard" + +# This is the node affinity settings as defined in +# https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#node-affinity-beta-feature +nodeAffinity: {} + +# The default is to deploy all pods serially. By setting this to parallel all pods are started at +# the same time when bootstrapping the cluster +podManagementPolicy: "Parallel" + +# The environment variables injected by service links are not used, but can lead to slow Elasticsearch boot times when +# there are many services in the current namespace. +# If you experience slow pod startups you probably want to set this to `false`. +enableServiceLinks: true + +protocol: https +httpPort: 9200 +transportPort: 9300 + +service: + enabled: true + labels: {} + labelsHeadless: {} + type: ClusterIP + # Consider that all endpoints are considered "ready" even if the Pods themselves are not + # https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/#ServiceSpec + publishNotReadyAddresses: false + nodePort: "" + annotations: {} + httpPortName: http + transportPortName: transport + loadBalancerIP: "" + loadBalancerSourceRanges: [] + externalTrafficPolicy: "" + +updateStrategy: RollingUpdate + +# This is the max unavailable setting for the pod disruption budget +# The default value of 1 will make sure that kubernetes won't allow more than 1 +# of your pods to be unavailable during maintenance +maxUnavailable: 1 + +podSecurityContext: + fsGroup: 1000 + runAsUser: 1000 + +securityContext: + capabilities: + drop: + - ALL + # readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + +# How long to wait for elasticsearch to stop gracefully +terminationGracePeriod: 120 + +sysctlVmMaxMapCount: 262144 + +readinessProbe: + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 3 + timeoutSeconds: 5 + +# https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-health.html#request-params wait_for_status +clusterHealthCheckParams: "wait_for_status=green&timeout=1s" + +## Use an alternate scheduler. +## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ +## +schedulerName: "" + +imagePullSecrets: [] +nodeSelector: {} +tolerations: [] + +# Enabling this will publicly expose your Elasticsearch instance. +# Only enable this if you have security enabled on your cluster +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + className: "nginx" + pathtype: ImplementationSpecific + hosts: + - host: chart-example.local + paths: + - path: / + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +nameOverride: "" +fullnameOverride: "" +healthNameOverride: "" +lifecycle: {} +postStart: + exec: + command: + - /bin/bash + - -c + - | + exec > >(tee -a /poststart.log) 2>&1 + set -euo pipefail + ES_ENCODED_PASSWORD=$(printf "%s" "$ES_PASSWORD" | sed 's/%/%25/g') + echo "[postStart] Waiting for Elasticsearch to be ready..." >&2 + for ((i=1; i<=MAX_RETRIES; i++)); do + if /usr/bin/curl --cacert "$CA_CERT" -s -u "$ES_USERNAME:$ES_ENCODED_PASSWORD" "$ES_URL" >/dev/null; then + echo "[postStart] Elasticsearch is up after $i attempts!" >&2 + break + fi + if [ "$i" -eq "$MAX_RETRIES" ]; then + echo "[postStart] ERROR: Elasticsearch did not become ready after $MAX_RETRIES attempts." >&2 + exit 1 + fi + sleep 5 + done + echo "[postStart] Loading index template from $TEMPLATE_PATH" >&2 + if ! /usr/bin/curl --cacert "$CA_CERT" -X PUT "$ES_URL/chat_v1_idx" \ + -u "$ES_USERNAME:$ES_ENCODED_PASSWORD" \ + -H 'Content-Type: application/json' \ + --data-binary @"$TEMPLATE_PATH_1"; then + echo "[postStart] ERROR: Failed to apply index template!" >&2 + exit 1 + fi + if ! /usr/bin/curl --cacert "$CA_CERT" -X PUT "$ES_URL/message_v1_idx" \ + -u "$ES_USERNAME:$ES_ENCODED_PASSWORD" \ + -H 'Content-Type: application/json' \ + --data-binary @"$TEMPLATE_PATH_2"; then + echo "[postStart] ERROR: Failed to apply index template!" >&2 + exit 1 + fi + if ! /usr/bin/curl --cacert "$CA_CERT" -X PUT "$ES_URL/user_v1_idx" \ + -u "$ES_USERNAME:$ES_ENCODED_PASSWORD" \ + -H 'Content-Type: application/json' \ + --data-binary @"$TEMPLATE_PATH_3"; then + echo "[postStart] ERROR: Failed to apply index template!" >&2 + exit 1 + fi + echo "[postStart] Index template 'chat_v1_idx' applied." >&2 + + echo "Debug message" >> /poststart.log 2>&1 + +sysctlInitContainer: + enabled: true + +keystore: [] + +networkPolicy: + ## Enable creation of NetworkPolicy resources. Only Ingress traffic is filtered for now. + ## In order for a Pod to access Elasticsearch, it needs to have the following label: + ## {{ template "uname" . }}-client: "true" + ## Example for default configuration to access HTTP port: + ## elasticsearch-master-http-client: "true" + ## Example for default configuration to access transport port: + ## elasticsearch-master-transport-client: "true" + + http: + enabled: false + ## if explicitNamespacesSelector is not set or set to {}, only client Pods being in the networkPolicy's namespace + ## and matching all criteria can reach the DB. + ## But sometimes, we want the Pods to be accessible to clients from other namespaces, in this case, we can use this + ## parameter to select these namespaces + ## + # explicitNamespacesSelector: + # # Accept from namespaces with all those different rules (only from whitelisted Pods) + # matchLabels: + # role: frontend + # matchExpressions: + # - {key: role, operator: In, values: [frontend]} + + ## Additional NetworkPolicy Ingress "from" rules to set. Note that all rules are OR-ed. + ## + # additionalRules: + # - podSelector: + # matchLabels: + # role: frontend + # - podSelector: + # matchExpressions: + # - key: role + # operator: In + # values: + # - frontend + + transport: + ## Note that all Elasticsearch Pods can talk to themselves using transport port even if enabled. + enabled: false + # explicitNamespacesSelector: + # matchLabels: + # role: frontend + # matchExpressions: + # - {key: role, operator: In, values: [frontend]} + # additionalRules: + # - podSelector: + # matchLabels: + # role: frontend + # - podSelector: + # matchExpressions: + # - key: role + # operator: In + # values: + # - frontend + +tests: + enabled: true diff --git a/grafana/Chart.yaml b/grafana/Chart.yaml new file mode 100644 index 0000000..2845ff5 --- /dev/null +++ b/grafana/Chart.yaml @@ -0,0 +1,91 @@ +--- +apiVersion: v2 +name: k8s-monitoring +description: Capture all telemetry data from your Kubernetes cluster. +type: application +icon: https://raw.githubusercontent.com/grafana/grafana/main/public/img/grafana_icon.svg +sources: + - https://github.com/grafana/k8s-monitoring-helm/tree/main/charts/k8s-monitoring +version: 2.0.26 +appVersion: 2.0.26 +maintainers: + - email: pete.wall@grafana.com + name: petewall + - email: robert.lankford@grafana.com + name: rlankfo +dependencies: + - alias: annotationAutodiscovery + name: feature-annotation-autodiscovery + repository: "" + version: 1.0.0 + condition: annotationAutodiscovery.enabled + - alias: applicationObservability + name: feature-application-observability + repository: "" + version: 1.0.0 + condition: applicationObservability.enabled + - alias: autoInstrumentation + name: feature-auto-instrumentation + repository: "" + version: 1.0.0 + condition: autoInstrumentation.enabled + - alias: clusterEvents + name: feature-cluster-events + repository: "" + version: 1.0.0 + condition: clusterEvents.enabled + - alias: clusterMetrics + name: feature-cluster-metrics + repository: "" + version: 1.0.0 + condition: clusterMetrics.enabled + - alias: integrations + name: feature-integrations + repository: "" + version: 1.0.0 + - alias: nodeLogs + name: feature-node-logs + repository: "" + version: 1.0.0 + condition: nodeLogs.enabled + - alias: podLogs + name: feature-pod-logs + repository: "" + version: 1.0.0 + condition: podLogs.enabled + - alias: profiling + name: feature-profiling + repository: "" + version: 1.0.0 + condition: profiling.enabled + - alias: prometheusOperatorObjects + name: feature-prometheus-operator-objects + repository: "" + version: 1.0.0 + condition: prometheusOperatorObjects.enabled + + - alias: alloy-metrics + name: alloy + version: 1.0.2 + repository: https://grafana.github.io/helm-charts + condition: alloy-metrics.enabled + - alias: alloy-singleton + name: alloy + version: 1.0.2 + repository: https://grafana.github.io/helm-charts + condition: alloy-singleton.enabled + - alias: alloy-logs + name: alloy + version: 1.0.2 + repository: https://grafana.github.io/helm-charts + condition: alloy-logs.enabled + - alias: alloy-receiver + name: alloy + version: 1.0.2 + repository: https://grafana.github.io/helm-charts + condition: alloy-receiver.enabled + - alias: alloy-profiles + name: alloy + version: 1.0.2 + repository: https://grafana.github.io/helm-charts + condition: alloy-profiles.enabled diff --git a/grafana/charts/alloy-1.0.2.tgz b/grafana/charts/alloy-1.0.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..5b7c317479a7874a1ac06c666d82cedc21846093 GIT binary patch literal 25353 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 /dev/null) + +.SECONDEXPANSION: +README.md: values.yaml Chart.yaml $$(wildcard README.md.gotmpl) +ifdef HAS_HELM_DOCS + helm-docs +else + docker run --rm --volume "$(shell pwd):/helm-docs" -u $(shell id -u) jnorwood/helm-docs:latest +endif + +Chart.lock: Chart.yaml + helm dependency update . + @touch Chart.lock # Ensure the timestamp is updated + +values.schema.json: values.yaml $$(wildcard schema-mods/*) + ../../../../scripts/schema-gen.sh . + +.PHONY: clean +clean: + rm -f README.md values.schema.json + +.PHONY: build +build: README.md Chart.lock values.schema.json + +.PHONY: test +test: build + helm lint . + ct lint --lint-conf ../../../../.configs/lintconf.yaml --helm-dependency-extra-args=--skip-refresh --charts . +ifdef HAS_HELM_UNITTEST + helm unittest . +else + docker run --rm --volume $(shell pwd):/apps helmunittest/helm-unittest:3.17.0-0.7.1 . +endif diff --git a/grafana/charts/feature-annotation-autodiscovery/README.md b/grafana/charts/feature-annotation-autodiscovery/README.md new file mode 100644 index 0000000..d0b74d4 --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/README.md @@ -0,0 +1,144 @@ + + +# feature-annotation-autodiscovery + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) +Gathers metrics automatically based on Kubernetes Pod and Service annotations + +The annotation-based autodiscovery feature adds scrape targets based on Kubernetes annotations. + +## How it works + +With this feature enabled, any Kubernetes Pods or Services with the `k8s.grafana.com/scrape` annotation set to `true` will be automatically discovered +and scraped by the collector. + +You can use several other annotations to customize the behavior of the scrape configuration, such as: + +* `k8s.grafana.com/job`: The value to use for the `job` label. +* `k8s.grafana.com/instance`: The value to use for the `instance` label. +* `k8s.grafana.com/metrics.path`: The path to scrape for metrics. Defaults to `/metrics`. +* `k8s.grafana.com/metrics.portNumber`: The port on the Pod or Service to scrape for metrics. This is used to target a specific port by its number, rather than all ports. +* `k8s.grafana.com/metrics.portName`: The named port on the Pod or Service to scrape for metrics. This is used to target a specific port by its name, rather than all ports. +* `k8s.grafana.com/metrics.scheme`: The scheme to use when scraping metrics. Defaults to `http`. +* `k8s.grafana.com/metrics.scrapeInterval`: The scrape interval to use when scraping metrics. Defaults to `60s`. + +## Testing + +This chart contains unit tests to verify the generated configuration. The hidden value `deployAsConfigMap` will render +the generated configuration into a ConfigMap object. While this ConfigMap is not used during regular operation, you can +use it to show the outcome of a given values file. + +The unit tests use this ConfigMap to create an object with the configuration that can be asserted against. To run the +tests, use `helm test`. + +Be sure perform actual integration testing in a live environment in the main [k8s-monitoring](../..) chart. + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| petewall | | | + + +## Source Code + +* + + + +## Values + +### Annotations + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| annotations.instance | string | `"k8s.grafana.com/instance"` | Annotation for overriding the instance label | +| annotations.job | string | `"k8s.grafana.com/job"` | Annotation for overriding the job label | +| annotations.metricsContainer | string | `"k8s.grafana.com/metrics.container"` | Annotation for selecting the specific container to scrape. | +| annotations.metricsParam | string | `"k8s.grafana.com/metrics.param"` | Annotation for setting `__param_` parameters when scraping. Example: `k8s.grafana.com/metrics.param_key: "value"`. | +| annotations.metricsPath | string | `"k8s.grafana.com/metrics.path"` | Annotation for setting or overriding the metrics path. If not set, it defaults to /metrics | +| annotations.metricsPortName | string | `"k8s.grafana.com/metrics.portName"` | Annotation for setting the metrics port by name. | +| annotations.metricsPortNumber | string | `"k8s.grafana.com/metrics.portNumber"` | Annotation for setting the metrics port by number. | +| annotations.metricsScheme | string | `"k8s.grafana.com/metrics.scheme"` | Annotation for setting the metrics scheme, default: http. | +| annotations.metricsScrapeInterval | string | `"k8s.grafana.com/metrics.scrapeInterval"` | Annotation for overriding the scrape interval for this service or pod. Value should be a duration like "15s, 1m". Overrides metrics.autoDiscover.scrapeInterval | +| annotations.metricsScrapeTimeout | string | `"k8s.grafana.com/metrics.scrapeTimeout"` | Annotation for overriding the scrape timeout for this service or pod. Value should be a duration like "15s, 1m". Overrides metrics.autoDiscover.scrapeTimeout | +| annotations.scrape | string | `"k8s.grafana.com/scrape"` | Annotation for enabling scraping for this service or pod. Value should be either "true" or "false" | + +### Scrape Settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| bearerToken | object | `{"enabled":true,"token":"/var/run/secrets/kubernetes.io/serviceaccount/token"}` | Sets bearer_token_file line in the prometheus.scrape annotation_autodiscovery. | +| scrapeInterval | string | 60s | How frequently to scrape metrics from discovered pods and services. Only used if the `k8s.grafana.com/metrics.scrapeInterval` annotation is not set. Overrides global.scrapeInterval | +| scrapeTimeout | string | 10s | The scrape timeout for discovered pods and services. Only used if the `k8s.grafana.com/metrics.scrapeTimeout` annotation is not set. Overrides global.scrapeTimeout | + +### Discovery Settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| excludeNamespaces | list | `[]` | The list of namespaces to exclude from autodiscovery. | +| extraDiscoveryRules | string | `""` | Rule blocks to be added to the discovery.relabel component for discovered pods and services. These relabeling rules are applied pre-scrape against the targets from service discovery. Before the scrape, any remaining target labels that start with `__` (i.e. `__meta_kubernetes*`) are dropped. ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) | +| labelSelectors | object | `{}` | Filter the list of discovered pods and services by labels. Example: `labelSelectors: { 'app': 'myapp' }` will only discover pods and services with the label `app=myapp`. Example: `labelSelectors: { 'app': ['myapp', 'myotherapp'] }` will only discover pods and services with the label `app=myapp` or `app=myotherapp`. | +| namespaces | list | `[]` | The list of namespaces to include in autodiscovery. If empty, all namespaces are included. | + +### Metric Processing Settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| extraMetricProcessingRules | string | `""` | Rule blocks to be added to the prometheus.relabel component for discovered pods and services. These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no `__meta*` labels are present. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#rule-block)) | +| maxCacheSize | string | `nil` | Sets the max_cache_size for cadvisor prometheus.relabel component. This should be at least 2x-5x your largest scrape target or samples appended rate. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) Overrides global.maxCacheSize | +| metricsTuning.excludeMetrics | list | `[]` | Metrics to drop. Can use regular expressions. | +| metricsTuning.includeMetrics | list | `[]` | Metrics to keep. Can use regular expressions. | + +### General settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| fullnameOverride | string | `""` | Full name override | +| nameOverride | string | `""` | Name override | + +### Global Settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| global.maxCacheSize | int | `100000` | Sets the max_cache_size for every prometheus.relabel component. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) This should be at least 2x-5x your largest scrape target or samples appended rate. | +| global.scrapeInterval | string | `"60s"` | How frequently to scrape metrics. | +| global.scrapeTimeout | string | `"10s"` | The scrape timeout for discovered pods and services. | + +### Pod Discovery Settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| pods.enabled | bool | `true` | Enable discovering Pods with annotations. | +| pods.labelSelectors | object | `{}` | Filter the list of discovered Pods by labels. Example: `labelSelectors: { 'app': 'myapp' }` will only discover Pods with the label `app=myapp`. Example: `labelSelectors: { 'app': ['myapp', 'myotherapp'] }` will only discover Pods with the label `app=myapp` or `app=myotherapp`. | + +### Pod Metric Processing Settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| pods.labels | object | `{}` | Add labels to metrics from discovered Pods. Runs during discovery, so __meta_ labels are available. See the [documentation](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.kubernetes/#pod-role) for the full list of meta labels. | +| pods.staticLabels | object | `{}` | Metric labels to set with static data for discovered Pods. | +| pods.staticLabelsFrom | object | `{}` | Static labels to set on metrics from discovered Pods, not quoted so it can reference config components. | + +### Services + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| services.enabled | bool | `true` | Enable discovering Services with annotations. | + +### Service Discovery Settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| services.labelSelectors | object | `{}` | Filter the list of discovered Services by labels. Example: `labelSelectors: { 'app': 'myapp' }` will only discover Services with the label `app=myapp`. Example: `labelSelectors: { 'app': ['myapp', 'myotherapp'] }` will only discover Services with the label `app=myapp` or `app=myotherapp`. | + +### Service Metric Processing Settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| services.labels | object | `{}` | Add labels to metrics from discovered Services. Run during discovery, so __meta_ labels are available. See the [documentation](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.kubernetes/#service-role) for the full list of meta labels. | +| services.staticLabels | object | `{}` | Metric labels to set with static data for discovered Services. | +| services.staticLabelsFrom | object | `{}` | Static labels to set on metrics from discovered Services, not quoted so it can reference config components. | diff --git a/grafana/charts/feature-annotation-autodiscovery/README.md.gotmpl b/grafana/charts/feature-annotation-autodiscovery/README.md.gotmpl new file mode 100644 index 0000000..7fea4b6 --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/README.md.gotmpl @@ -0,0 +1,47 @@ + + +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} +{{ template "chart.badgesSection" . }} +{{ template "chart.description" . }} +{{ template "chart.homepageLine" . }} + +The annotation-based autodiscovery feature adds scrape targets based on Kubernetes annotations. + +## How it works + +With this feature enabled, any Kubernetes Pods or Services with the `k8s.grafana.com/scrape` annotation set to `true` will be automatically discovered +and scraped by the collector. + +You can use several other annotations to customize the behavior of the scrape configuration, such as: + +* `k8s.grafana.com/job`: The value to use for the `job` label. +* `k8s.grafana.com/instance`: The value to use for the `instance` label. +* `k8s.grafana.com/metrics.path`: The path to scrape for metrics. Defaults to `/metrics`. +* `k8s.grafana.com/metrics.portNumber`: The port on the Pod or Service to scrape for metrics. This is used to target a specific port by its number, rather than all ports. +* `k8s.grafana.com/metrics.portName`: The named port on the Pod or Service to scrape for metrics. This is used to target a specific port by its name, rather than all ports. +* `k8s.grafana.com/metrics.scheme`: The scheme to use when scraping metrics. Defaults to `http`. +* `k8s.grafana.com/metrics.scrapeInterval`: The scrape interval to use when scraping metrics. Defaults to `60s`. + +## Testing + +This chart contains unit tests to verify the generated configuration. The hidden value `deployAsConfigMap` will render +the generated configuration into a ConfigMap object. While this ConfigMap is not used during regular operation, you can +use it to show the outcome of a given values file. + +The unit tests use this ConfigMap to create an object with the configuration that can be asserted against. To run the +tests, use `helm test`. + +Be sure perform actual integration testing in a live environment in the main [k8s-monitoring](../..) chart. + +{{ template "chart.maintainersSection" . }} + + +{{ template "chart.sourcesSection" . }} + + +{{ template "chart.requirementsSection" . }} +{{ template "chart.valuesSection" . }} diff --git a/grafana/charts/feature-annotation-autodiscovery/templates/_helpers.tpl b/grafana/charts/feature-annotation-autodiscovery/templates/_helpers.tpl new file mode 100644 index 0000000..b96319f --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/templates/_helpers.tpl @@ -0,0 +1,37 @@ +{{/* +Create a default fully qualified 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 "feature.annotationAutodiscovery.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" | lower }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride | lower }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" | lower }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" | lower }} +{{- end }} +{{- end }} +{{- end }} + +{{- define "escape_label_or_annotation" -}} +{{ . | replace "-" "_" | replace "." "_" | replace "/" "_" }} +{{- end }} + +{{- define "pod_annotation" -}} +{{ printf "__meta_kubernetes_pod_annotation_%s" (include "escape_label_or_annotation" .) }} +{{- end }} + +{{- define "pod_label" -}} +{{ printf "__meta_kubernetes_pod_label_%s" (include "escape_label_or_annotation" .) }} +{{- end }} + +{{- define "service_annotation" -}} +{{ printf "__meta_kubernetes_service_annotation_%s" (include "escape_label_or_annotation" .) }} +{{- end }} + +{{- define "service_label" -}} +{{ printf "__meta_kubernetes_service_label_%s" (include "escape_label_or_annotation" .) }} +{{- end }} diff --git a/grafana/charts/feature-annotation-autodiscovery/templates/_module.alloy.tpl b/grafana/charts/feature-annotation-autodiscovery/templates/_module.alloy.tpl new file mode 100644 index 0000000..c908e8d --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/templates/_module.alloy.tpl @@ -0,0 +1,139 @@ +{{- define "feature.annotationAutodiscovery.module" }} +declare "annotation_autodiscovery" { + argument "metrics_destinations" { + comment = "Must be a list of metric destinations where collected metrics should be forwarded to" + } +{{- if .Values.pods.enabled }} + {{- include "feature.annotationAutodiscovery.pods" . | indent 2 }} +{{- end }} +{{- if .Values.services.enabled }} +{{- include "feature.annotationAutodiscovery.services" . | indent 2 }} +{{- end }} + +{{- $targets := list }} +{{- if .Values.pods.enabled }} + {{- $targets = append $targets "discovery.relabel.annotation_autodiscovery_pods.output" }} +{{- end }} +{{- if .Values.services.enabled }} + {{- $targets = append $targets "discovery.relabel.annotation_autodiscovery_services.output" }} +{{- end }} + + discovery.relabel "annotation_autodiscovery_http" { + targets = array.concat({{ $targets | join ", " }}) + rule { + source_labels = ["__scheme__"] + regex = "https" + action = "drop" + } + } + + discovery.relabel "annotation_autodiscovery_https" { + targets = array.concat({{ $targets | join ", " }}) + rule { + source_labels = ["__scheme__"] + regex = "https" + action = "keep" + } + } + + prometheus.scrape "annotation_autodiscovery_http" { + targets = discovery.relabel.annotation_autodiscovery_http.output + honor_labels = true +{{- if .Values.bearerToken.enabled }} + bearer_token_file = {{ .Values.bearerToken.token | quote }} +{{- end }} + clustering { + enabled = true + } +{{- $metricRelabelRulesNeeded := or .Values.metricsTuning.includeMetrics .Values.metricsTuning.excludeMetrics .Values.extraMetricProcessingRules }} +{{- $metricRelabelRulesNeeded = or $metricRelabelRulesNeeded (and .Values.pods.enabled (or .Values.pods.staticLabels .Values.pods.staticLabelsFrom)) }} +{{- $metricRelabelRulesNeeded = or $metricRelabelRulesNeeded (and .Values.services.enabled (or .Values.services.staticLabels .Values.services.staticLabelsFrom)) }} +{{ if $metricRelabelRulesNeeded }} + forward_to = [prometheus.relabel.annotation_autodiscovery.receiver] +{{- else }} + forward_to = argument.metrics_destinations.value +{{- end }} + } + + prometheus.scrape "annotation_autodiscovery_https" { + targets = discovery.relabel.annotation_autodiscovery_https.output + honor_labels = true +{{- if .Values.bearerToken.enabled }} + bearer_token_file = {{ .Values.bearerToken.token | quote }} +{{- end }} + tls_config { + insecure_skip_verify = true + } + clustering { + enabled = true + } +{{ if $metricRelabelRulesNeeded }} + forward_to = [prometheus.relabel.annotation_autodiscovery.receiver] + } + + prometheus.relabel "annotation_autodiscovery" { + max_cache_size = {{ .Values.maxCacheSize | default .Values.global.maxCacheSize | int }} +{{- if .Values.metricsTuning.includeMetrics }} + rule { + source_labels = ["__name__"] + regex = "up|scrape_samples_scraped|{{ join "|" .Values.metricsTuning.includeMetrics }}" + action = "keep" + } +{{- end }} +{{- if .Values.metricsTuning.excludeMetrics }} + rule { + source_labels = ["__name__"] + regex = {{ join "|" .Values.metricsTuning.excludeMetrics | quote }} + action = "drop" + } +{{- end }} +{{- if .Values.pods.enabled }} +{{- range $k, $v := .Values.pods.staticLabels }} + rule { + source_labels = ["temp_source"] + regex = "pod" + target_label = {{ $k | quote }} + replacement = {{ $v | quote }} + } +{{- end }} +{{- range $k, $v := .Values.pods.staticLabelsFrom }} + rule { + source_labels = ["temp_source"] + regex = "pod" + target_label = {{ $k | quote }} + replacement = {{ $v }} + } +{{- end }} +{{- end }} +{{- if .Values.services.enabled }} +{{- range $k, $v := .Values.services.staticLabels }} + rule { + source_labels = ["temp_source"] + regex = "service" + target_label = {{ $k | quote }} + replacement = {{ $v | quote }} + } +{{- end }} +{{- range $k, $v := .Values.services.staticLabelsFrom }} + rule { + source_labels = ["temp_source"] + regex = "service" + target_label = {{ $k | quote }} + replacement = {{ $v }} + } +{{- end }} +{{- end }} + rule { + action = "labeldrop" + regex = "temp_source" + } +{{- if .Values.extraMetricProcessingRules }} +{{ .Values.extraMetricProcessingRules | indent 4 }} +{{- end }} +{{- end }} + forward_to = argument.metrics_destinations.value + } +} +{{- end -}} + +{{- define "feature.annotationAutodiscovery.alloyModules" }}{{- end }} diff --git a/grafana/charts/feature-annotation-autodiscovery/templates/_notes.tpl b/grafana/charts/feature-annotation-autodiscovery/templates/_notes.tpl new file mode 100644 index 0000000..94939a7 --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/templates/_notes.tpl @@ -0,0 +1,11 @@ +{{- define "feature.annotationAutodiscovery.notes.deployments" }}{{- end }} + +{{- define "feature.annotationAutodiscovery.notes.task" }} +Scrape metrics from pods and services with the "{{.Values.annotations.scrape}}: true" annotation +{{- end }} + +{{- define "feature.annotationAutodiscovery.notes.actions" }}{{- end }} + +{{- define "feature.annotationAutodiscovery.summary" -}} +version: {{ .Chart.Version }} +{{- end }} diff --git a/grafana/charts/feature-annotation-autodiscovery/templates/_pods.alloy.tpl b/grafana/charts/feature-annotation-autodiscovery/templates/_pods.alloy.tpl new file mode 100644 index 0000000..e87c3bd --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/templates/_pods.alloy.tpl @@ -0,0 +1,193 @@ +{{- define "feature.annotationAutodiscovery.pods" }} + +discovery.kubernetes "pods" { + role = "pod" +{{- if .Values.namespaces }} + namespaces { + names = {{ .Values.namespaces | toJson }} + } +{{- end }} +{{- $labelSelectors := list }} +{{- range $k, $v := .Values.labelSelectors }} + {{- if kindIs "slice" $v }} + {{- $labelSelectors = append $labelSelectors (printf "%s in (%s)" $k (join "," $v)) }} + {{- else }} + {{- $labelSelectors = append $labelSelectors (printf "%s=%s" $k $v) }} + {{- end }} +{{- end }} +{{- range $k, $v := .Values.pods.labelSelectors }} + {{- if kindIs "slice" $v }} + {{- $labelSelectors = append $labelSelectors (printf "%s in (%s)" $k (join "," $v)) }} + {{- else }} + {{- $labelSelectors = append $labelSelectors (printf "%s=%s" $k $v) }} + {{- end }} +{{- end }} +{{- if $labelSelectors }} + selectors { + role = "pod" + label = {{ $labelSelectors | join "," | quote }} + } +{{- end }} +} + +discovery.relabel "annotation_autodiscovery_pods" { + targets = discovery.kubernetes.pods.targets +{{- if .Values.excludeNamespaces }} + rule { + source_labels = ["__meta_kubernetes_namespace"] + regex = "{{ join "|" .Values.excludeNamespaces }}" + action = "drop" + } +{{- end }} + rule { + source_labels = ["{{ include "pod_annotation" .Values.annotations.scrape }}"] + regex = "true" + action = "keep" + } + // Only keep pods that are running, ready, and not init containers. + rule { + source_labels = [ + "__meta_kubernetes_pod_phase", + "__meta_kubernetes_pod_ready", + "__meta_kubernetes_pod_container_init", + ] + regex = "Running;true;false" + action = "keep" + } + rule { + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + rule { + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + rule { + source_labels = ["{{ include "pod_annotation" .Values.annotations.job }}"] + target_label = "job" + } + rule { + source_labels = ["{{ include "pod_annotation" .Values.annotations.instance }}"] + target_label = "instance" + } + + // Rules to choose the right container + rule { + source_labels = ["container"] + target_label = "__tmp_container" + } + rule { + source_labels = ["{{ include "pod_annotation" .Values.annotations.metricsContainer }}"] + regex = "(.+)" + target_label = "__tmp_container" + } + rule { + source_labels = ["container"] + action = "keepequal" + target_label = "__tmp_container" + } + rule { + action = "labeldrop" + regex = "__tmp_container" + } + + // Set metrics path + rule { + source_labels = ["{{ include "pod_annotation" .Values.annotations.metricsPath }}"] + regex = "(.+)" + target_label = "__metrics_path__" + } + + // Set metrics scraping URL parameters + rule { + action = "labelmap" + regex = "{{ include "pod_annotation" .Values.annotations.metricsParam }}_(.+)" + replacement = "__param_$1" + } + + // Choose the pod port + // The discovery generates a target for each declared container port of the pod. + // If the metricsPortName annotation has value, keep only the target where the port name matches the one of the annotation. + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__tmp_port" + } + rule { + source_labels = ["{{ include "pod_annotation" .Values.annotations.metricsPortName }}"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + action = "keepequal" + target_label = "__tmp_port" + } + rule { + action = "labeldrop" + regex = "__tmp_port" + } + + // If the metrics port number annotation has a value, override the target address to use it, regardless whether it is + // one of the declared ports on that Pod. + rule { + source_labels = ["{{ include "pod_annotation" .Values.annotations.metricsPortNumber }}", "__meta_kubernetes_pod_ip"] + regex = "(\\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})" + replacement = "[$2]:$1" // IPv6 + target_label = "__address__" + } + rule { + source_labels = ["{{ include "pod_annotation" .Values.annotations.metricsPortNumber }}", "__meta_kubernetes_pod_ip"] + regex = "(\\d+);((([0-9]+?)(\\.|$)){4})" // IPv4, takes priority over IPv6 when both exists + replacement = "$2:$1" + target_label = "__address__" + } + + rule { + source_labels = ["{{ include "pod_annotation" .Values.annotations.metricsScheme }}"] + regex = "(.+)" + target_label = "__scheme__" + } + + rule { + source_labels = ["{{ include "pod_annotation" .Values.annotations.metricsScrapeInterval }}"] + regex = "(.+)" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__scrape_interval__"] + regex = "" + replacement = {{ .Values.scrapeInterval | default .Values.global.scrapeInterval | quote }} + target_label = "__scrape_interval__" + } + rule { + source_labels = ["{{ include "pod_annotation" .Values.annotations.metricsScrapeTimeout }}"] + regex = "(.+)" + target_label = "__scrape_timeout__" + } + rule { + source_labels = ["__scrape_timeout__"] + regex = "" + replacement = {{ .Values.scrapeTimeout | default .Values.global.scrapeTimeout | quote }} + target_label = "__scrape_timeout__" + } +{{- range $metricLabel, $k8sLabel := .Values.pods.labels }} + rule { + source_labels = ["{{ include "pod_label" $k8sLabel }}"] + target_label = "{{ $metricLabel }}" + } +{{- end }} +{{- if or .Values.pods.staticLabels .Values.pods.staticLabelsFrom }} + rule { + target_label = "temp_source" + replacement = "pod" + } +{{- end }} +{{- if .Values.extraDiscoveryRules }} +{{ .Values.extraDiscoveryRules | indent 4 }} +{{- end }} +} +{{- end -}} diff --git a/grafana/charts/feature-annotation-autodiscovery/templates/_services.alloy.tpl b/grafana/charts/feature-annotation-autodiscovery/templates/_services.alloy.tpl new file mode 100644 index 0000000..74dee0e --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/templates/_services.alloy.tpl @@ -0,0 +1,156 @@ +{{- define "feature.annotationAutodiscovery.services" }} + +discovery.kubernetes "services" { + role = "service" +{{- if .Values.namespaces }} + namespaces { + names = {{ .Values.namespaces | toJson }} + } +{{- end }} +{{- $labelSelectors := list }} +{{- range $k, $v := .Values.labelSelectors }} + {{- if kindIs "slice" $v }} + {{- $labelSelectors = append $labelSelectors (printf "%s in (%s)" $k (join "," $v)) }} + {{- else }} + {{- $labelSelectors = append $labelSelectors (printf "%s=%s" $k $v) }} + {{- end }} +{{- end }} +{{- range $k, $v := .Values.services.labelSelectors }} + {{- if kindIs "slice" $v }} + {{- $labelSelectors = append $labelSelectors (printf "%s in (%s)" $k (join "," $v)) }} + {{- else }} + {{- $labelSelectors = append $labelSelectors (printf "%s=%s" $k $v) }} + {{- end }} +{{- end }} +{{- if $labelSelectors }} + selectors { + role = "service" + label = {{ $labelSelectors | join "," | quote }} + } +{{- end }} +} + +discovery.relabel "annotation_autodiscovery_services" { + targets = discovery.kubernetes.services.targets +{{- if .Values.excludeNamespaces }} + rule { + source_labels = ["__meta_kubernetes_namespace"] + regex = "{{ join "|" .Values.excludeNamespaces }}" + action = "drop" + } +{{- end }} + rule { + source_labels = ["{{ include "service_annotation" .Values.annotations.scrape }}"] + regex = "true" + action = "keep" + } + rule { + source_labels = ["__meta_kubernetes_service_name"] + target_label = "service" + } + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + rule { + source_labels = ["{{ include "service_annotation" .Values.annotations.job }}"] + target_label = "job" + } + rule { + source_labels = ["{{ include "service_annotation" .Values.annotations.instance }}"] + target_label = "instance" + } + + // Set metrics path + rule { + source_labels = ["{{ include "service_annotation" .Values.annotations.metricsPath }}"] + target_label = "__metrics_path__" + } + + // Set metrics scraping URL parameters + rule { + action = "labelmap" + regex = "{{ include "service_annotation" .Values.annotations.metricsParam }}_(.+)" + replacement = "__param_$1" + } + + // Choose the service port + rule { + source_labels = ["__meta_kubernetes_service_port_name"] + target_label = "__tmp_port" + } + rule { + source_labels = ["{{ include "service_annotation" .Values.annotations.metricsPortName }}"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_port_name"] + action = "keepequal" + target_label = "__tmp_port" + } + + rule { + source_labels = ["__meta_kubernetes_service_port_number"] + target_label = "__tmp_port" + } + rule { + source_labels = ["{{ include "service_annotation" .Values.annotations.metricsPortNumber }}"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_port_number"] + action = "keepequal" + target_label = "__tmp_port" + } + rule { + action = "labeldrop" + regex = "__tmp_port" + } + + rule { + source_labels = ["{{ include "service_annotation" .Values.annotations.metricsScheme }}"] + regex = "(.+)" + target_label = "__scheme__" + } + + rule { + source_labels = ["{{ include "service_annotation" .Values.annotations.metricsScrapeInterval }}"] + regex = "(.+)" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__scrape_interval__"] + regex = "" + replacement = {{ .Values.scrapeInterval | default .Values.global.scrapeInterval | quote }} + target_label = "__scrape_interval__" + } + rule { + source_labels = ["{{ include "service_annotation" .Values.annotations.metricsScrapeTimeout }}"] + regex = "(.+)" + target_label = "__scrape_timeout__" + } + rule { + source_labels = ["__scrape_timeout__"] + regex = "" + replacement = {{ .Values.scrapeTimeout | default .Values.global.scrapeTimeout | quote }} + target_label = "__scrape_timeout__" + } +{{- range $metricLabel, $k8sLabel := .Values.services.labels }} + rule { + source_labels = ["{{ include "service_label" $k8sLabel }}"] + target_label = "{{ $metricLabel }}" + } +{{- end }} +{{- if or .Values.pods.staticLabels .Values.pods.staticLabelsFrom }} + rule { + target_label = "temp_source" + replacement = "service" + } +{{- end }} +{{- if .Values.extraDiscoveryRules }} +{{ .Values.extraDiscoveryRules | indent 4 }} +{{- end }} +} +{{- end -}} diff --git a/grafana/charts/feature-annotation-autodiscovery/templates/_validation.tpl b/grafana/charts/feature-annotation-autodiscovery/templates/_validation.tpl new file mode 100644 index 0000000..f47df11 --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/templates/_validation.tpl @@ -0,0 +1,14 @@ +{{- define "feature.annotationAutodiscovery.validate" }} +{{- if and (not .Values.pods.enabled) (not .Values.services.enabled) }} + {{- $msg := list "" "Either Pods or Services must be enabled for this feature to work." }} + {{- $msg = append $msg "Please enable one or both. For example:" }} + {{- $msg = append $msg "annotationAutodiscovery:" }} + {{- $msg = append $msg " pods:" }} + {{- $msg = append $msg " enabled: true" }} + {{- $msg = append $msg "AND/OR" }} + {{- $msg = append $msg " services:" }} + {{- $msg = append $msg " enabled: true" }} + {{- $msg = append $msg "See https://github.com/grafana/k8s-monitoring-helm/tree/main/charts/k8s-monitoring/charts/feature-annotation-autodiscovery for more details." }} + {{- fail (join "\n" $msg) }} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-annotation-autodiscovery/templates/configmap.yaml b/grafana/charts/feature-annotation-autodiscovery/templates/configmap.yaml new file mode 100644 index 0000000..3c9fe9e --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/templates/configmap.yaml @@ -0,0 +1,13 @@ +{{- if .Values.deployAsConfigMap }} +{{- $alloyConfig := include "feature.annotationAutodiscovery.module" . }} +{{- $alloyConfig = regexReplaceAll `[ \t]+(\r?\n)` $alloyConfig "\n" }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "feature.annotationAutodiscovery.fullname" . }} + namespace: {{ .Release.Namespace }} +data: + module.alloy: |- + {{- $alloyConfig | trim | nindent 4 }} +{{- end }} diff --git a/grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/.gitkeep b/grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/default_test.yaml.snap b/grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/default_test.yaml.snap new file mode 100644 index 0000000..7030dd8 --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/default_test.yaml.snap @@ -0,0 +1,300 @@ +creates a module with default discovery, scraping, and processing configurations: + 1: | + |- + declare "annotation_autodiscovery" { + argument "metrics_destinations" { + comment = "Must be a list of metric destinations where collected metrics should be forwarded to" + } + + discovery.kubernetes "pods" { + role = "pod" + } + + discovery.relabel "annotation_autodiscovery_pods" { + targets = discovery.kubernetes.pods.targets + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_scrape"] + regex = "true" + action = "keep" + } + // Only keep pods that are running, ready, and not init containers. + rule { + source_labels = [ + "__meta_kubernetes_pod_phase", + "__meta_kubernetes_pod_ready", + "__meta_kubernetes_pod_container_init", + ] + regex = "Running;true;false" + action = "keep" + } + rule { + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + rule { + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_job"] + target_label = "job" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_instance"] + target_label = "instance" + } + + // Rules to choose the right container + rule { + source_labels = ["container"] + target_label = "__tmp_container" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_container"] + regex = "(.+)" + target_label = "__tmp_container" + } + rule { + source_labels = ["container"] + action = "keepequal" + target_label = "__tmp_container" + } + rule { + action = "labeldrop" + regex = "__tmp_container" + } + + // Set metrics path + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_path"] + regex = "(.+)" + target_label = "__metrics_path__" + } + + // Set metrics scraping URL parameters + rule { + action = "labelmap" + regex = "__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_param_(.+)" + replacement = "__param_$1" + } + + // Choose the pod port + // The discovery generates a target for each declared container port of the pod. + // If the metricsPortName annotation has value, keep only the target where the port name matches the one of the annotation. + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portName"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + action = "keepequal" + target_label = "__tmp_port" + } + rule { + action = "labeldrop" + regex = "__tmp_port" + } + + // If the metrics port number annotation has a value, override the target address to use it, regardless whether it is + // one of the declared ports on that Pod. + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portNumber", "__meta_kubernetes_pod_ip"] + regex = "(\\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})" + replacement = "[$2]:$1" // IPv6 + target_label = "__address__" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portNumber", "__meta_kubernetes_pod_ip"] + regex = "(\\d+);((([0-9]+?)(\\.|$)){4})" // IPv4, takes priority over IPv6 when both exists + replacement = "$2:$1" + target_label = "__address__" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_scheme"] + regex = "(.+)" + target_label = "__scheme__" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_scrapeInterval"] + regex = "(.+)" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__scrape_interval__"] + regex = "" + replacement = "60s" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_scrapeTimeout"] + regex = "(.+)" + target_label = "__scrape_timeout__" + } + rule { + source_labels = ["__scrape_timeout__"] + regex = "" + replacement = "10s" + target_label = "__scrape_timeout__" + } + } + + discovery.kubernetes "services" { + role = "service" + } + + discovery.relabel "annotation_autodiscovery_services" { + targets = discovery.kubernetes.services.targets + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_scrape"] + regex = "true" + action = "keep" + } + rule { + source_labels = ["__meta_kubernetes_service_name"] + target_label = "service" + } + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_job"] + target_label = "job" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_instance"] + target_label = "instance" + } + + // Set metrics path + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_path"] + target_label = "__metrics_path__" + } + + // Set metrics scraping URL parameters + rule { + action = "labelmap" + regex = "__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_param_(.+)" + replacement = "__param_$1" + } + + // Choose the service port + rule { + source_labels = ["__meta_kubernetes_service_port_name"] + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_portName"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_port_name"] + action = "keepequal" + target_label = "__tmp_port" + } + + rule { + source_labels = ["__meta_kubernetes_service_port_number"] + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_portNumber"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_port_number"] + action = "keepequal" + target_label = "__tmp_port" + } + rule { + action = "labeldrop" + regex = "__tmp_port" + } + + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_scheme"] + regex = "(.+)" + target_label = "__scheme__" + } + + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_scrapeInterval"] + regex = "(.+)" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__scrape_interval__"] + regex = "" + replacement = "60s" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_scrapeTimeout"] + regex = "(.+)" + target_label = "__scrape_timeout__" + } + rule { + source_labels = ["__scrape_timeout__"] + regex = "" + replacement = "10s" + target_label = "__scrape_timeout__" + } + } + + discovery.relabel "annotation_autodiscovery_http" { + targets = array.concat(discovery.relabel.annotation_autodiscovery_pods.output, discovery.relabel.annotation_autodiscovery_services.output) + rule { + source_labels = ["__scheme__"] + regex = "https" + action = "drop" + } + } + + discovery.relabel "annotation_autodiscovery_https" { + targets = array.concat(discovery.relabel.annotation_autodiscovery_pods.output, discovery.relabel.annotation_autodiscovery_services.output) + rule { + source_labels = ["__scheme__"] + regex = "https" + action = "keep" + } + } + + prometheus.scrape "annotation_autodiscovery_http" { + targets = discovery.relabel.annotation_autodiscovery_http.output + honor_labels = true + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + clustering { + enabled = true + } + + forward_to = argument.metrics_destinations.value + } + + prometheus.scrape "annotation_autodiscovery_https" { + targets = discovery.relabel.annotation_autodiscovery_https.output + honor_labels = true + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + tls_config { + insecure_skip_verify = true + } + clustering { + enabled = true + } + + forward_to = argument.metrics_destinations.value + } + } diff --git a/grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/namespaced_test.yaml.snap b/grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/namespaced_test.yaml.snap new file mode 100644 index 0000000..3daabec --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/namespaced_test.yaml.snap @@ -0,0 +1,616 @@ +can exclude a specified list of namespaces: + 1: | + |- + declare "annotation_autodiscovery" { + argument "metrics_destinations" { + comment = "Must be a list of metric destinations where collected metrics should be forwarded to" + } + + discovery.kubernetes "pods" { + role = "pod" + } + + discovery.relabel "annotation_autodiscovery_pods" { + targets = discovery.kubernetes.pods.targets + rule { + source_labels = ["__meta_kubernetes_namespace"] + regex = "a|b" + action = "drop" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_scrape"] + regex = "true" + action = "keep" + } + // Only keep pods that are running, ready, and not init containers. + rule { + source_labels = [ + "__meta_kubernetes_pod_phase", + "__meta_kubernetes_pod_ready", + "__meta_kubernetes_pod_container_init", + ] + regex = "Running;true;false" + action = "keep" + } + rule { + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + rule { + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_job"] + target_label = "job" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_instance"] + target_label = "instance" + } + + // Rules to choose the right container + rule { + source_labels = ["container"] + target_label = "__tmp_container" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_container"] + regex = "(.+)" + target_label = "__tmp_container" + } + rule { + source_labels = ["container"] + action = "keepequal" + target_label = "__tmp_container" + } + rule { + action = "labeldrop" + regex = "__tmp_container" + } + + // Set metrics path + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_path"] + regex = "(.+)" + target_label = "__metrics_path__" + } + + // Set metrics scraping URL parameters + rule { + action = "labelmap" + regex = "__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_param_(.+)" + replacement = "__param_$1" + } + + // Choose the pod port + // The discovery generates a target for each declared container port of the pod. + // If the metricsPortName annotation has value, keep only the target where the port name matches the one of the annotation. + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portName"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + action = "keepequal" + target_label = "__tmp_port" + } + rule { + action = "labeldrop" + regex = "__tmp_port" + } + + // If the metrics port number annotation has a value, override the target address to use it, regardless whether it is + // one of the declared ports on that Pod. + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portNumber", "__meta_kubernetes_pod_ip"] + regex = "(\\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})" + replacement = "[$2]:$1" // IPv6 + target_label = "__address__" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portNumber", "__meta_kubernetes_pod_ip"] + regex = "(\\d+);((([0-9]+?)(\\.|$)){4})" // IPv4, takes priority over IPv6 when both exists + replacement = "$2:$1" + target_label = "__address__" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_scheme"] + regex = "(.+)" + target_label = "__scheme__" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_scrapeInterval"] + regex = "(.+)" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__scrape_interval__"] + regex = "" + replacement = "60s" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_scrapeTimeout"] + regex = "(.+)" + target_label = "__scrape_timeout__" + } + rule { + source_labels = ["__scrape_timeout__"] + regex = "" + replacement = "10s" + target_label = "__scrape_timeout__" + } + } + + discovery.kubernetes "services" { + role = "service" + } + + discovery.relabel "annotation_autodiscovery_services" { + targets = discovery.kubernetes.services.targets + rule { + source_labels = ["__meta_kubernetes_namespace"] + regex = "a|b" + action = "drop" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_scrape"] + regex = "true" + action = "keep" + } + rule { + source_labels = ["__meta_kubernetes_service_name"] + target_label = "service" + } + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_job"] + target_label = "job" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_instance"] + target_label = "instance" + } + + // Set metrics path + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_path"] + target_label = "__metrics_path__" + } + + // Set metrics scraping URL parameters + rule { + action = "labelmap" + regex = "__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_param_(.+)" + replacement = "__param_$1" + } + + // Choose the service port + rule { + source_labels = ["__meta_kubernetes_service_port_name"] + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_portName"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_port_name"] + action = "keepequal" + target_label = "__tmp_port" + } + + rule { + source_labels = ["__meta_kubernetes_service_port_number"] + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_portNumber"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_port_number"] + action = "keepequal" + target_label = "__tmp_port" + } + rule { + action = "labeldrop" + regex = "__tmp_port" + } + + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_scheme"] + regex = "(.+)" + target_label = "__scheme__" + } + + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_scrapeInterval"] + regex = "(.+)" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__scrape_interval__"] + regex = "" + replacement = "60s" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_scrapeTimeout"] + regex = "(.+)" + target_label = "__scrape_timeout__" + } + rule { + source_labels = ["__scrape_timeout__"] + regex = "" + replacement = "10s" + target_label = "__scrape_timeout__" + } + } + + discovery.relabel "annotation_autodiscovery_http" { + targets = array.concat(discovery.relabel.annotation_autodiscovery_pods.output, discovery.relabel.annotation_autodiscovery_services.output) + rule { + source_labels = ["__scheme__"] + regex = "https" + action = "drop" + } + } + + discovery.relabel "annotation_autodiscovery_https" { + targets = array.concat(discovery.relabel.annotation_autodiscovery_pods.output, discovery.relabel.annotation_autodiscovery_services.output) + rule { + source_labels = ["__scheme__"] + regex = "https" + action = "keep" + } + } + + prometheus.scrape "annotation_autodiscovery_http" { + targets = discovery.relabel.annotation_autodiscovery_http.output + honor_labels = true + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + clustering { + enabled = true + } + + forward_to = argument.metrics_destinations.value + } + + prometheus.scrape "annotation_autodiscovery_https" { + targets = discovery.relabel.annotation_autodiscovery_https.output + honor_labels = true + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + tls_config { + insecure_skip_verify = true + } + clustering { + enabled = true + } + + forward_to = argument.metrics_destinations.value + } + } +can use a specified list of namespaces: + 1: | + |- + declare "annotation_autodiscovery" { + argument "metrics_destinations" { + comment = "Must be a list of metric destinations where collected metrics should be forwarded to" + } + + discovery.kubernetes "pods" { + role = "pod" + namespaces { + names = ["a","b"] + } + } + + discovery.relabel "annotation_autodiscovery_pods" { + targets = discovery.kubernetes.pods.targets + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_scrape"] + regex = "true" + action = "keep" + } + // Only keep pods that are running, ready, and not init containers. + rule { + source_labels = [ + "__meta_kubernetes_pod_phase", + "__meta_kubernetes_pod_ready", + "__meta_kubernetes_pod_container_init", + ] + regex = "Running;true;false" + action = "keep" + } + rule { + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + rule { + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_job"] + target_label = "job" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_instance"] + target_label = "instance" + } + + // Rules to choose the right container + rule { + source_labels = ["container"] + target_label = "__tmp_container" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_container"] + regex = "(.+)" + target_label = "__tmp_container" + } + rule { + source_labels = ["container"] + action = "keepequal" + target_label = "__tmp_container" + } + rule { + action = "labeldrop" + regex = "__tmp_container" + } + + // Set metrics path + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_path"] + regex = "(.+)" + target_label = "__metrics_path__" + } + + // Set metrics scraping URL parameters + rule { + action = "labelmap" + regex = "__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_param_(.+)" + replacement = "__param_$1" + } + + // Choose the pod port + // The discovery generates a target for each declared container port of the pod. + // If the metricsPortName annotation has value, keep only the target where the port name matches the one of the annotation. + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portName"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + action = "keepequal" + target_label = "__tmp_port" + } + rule { + action = "labeldrop" + regex = "__tmp_port" + } + + // If the metrics port number annotation has a value, override the target address to use it, regardless whether it is + // one of the declared ports on that Pod. + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portNumber", "__meta_kubernetes_pod_ip"] + regex = "(\\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})" + replacement = "[$2]:$1" // IPv6 + target_label = "__address__" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portNumber", "__meta_kubernetes_pod_ip"] + regex = "(\\d+);((([0-9]+?)(\\.|$)){4})" // IPv4, takes priority over IPv6 when both exists + replacement = "$2:$1" + target_label = "__address__" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_scheme"] + regex = "(.+)" + target_label = "__scheme__" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_scrapeInterval"] + regex = "(.+)" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__scrape_interval__"] + regex = "" + replacement = "60s" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_scrapeTimeout"] + regex = "(.+)" + target_label = "__scrape_timeout__" + } + rule { + source_labels = ["__scrape_timeout__"] + regex = "" + replacement = "10s" + target_label = "__scrape_timeout__" + } + } + + discovery.kubernetes "services" { + role = "service" + namespaces { + names = ["a","b"] + } + } + + discovery.relabel "annotation_autodiscovery_services" { + targets = discovery.kubernetes.services.targets + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_scrape"] + regex = "true" + action = "keep" + } + rule { + source_labels = ["__meta_kubernetes_service_name"] + target_label = "service" + } + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_job"] + target_label = "job" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_instance"] + target_label = "instance" + } + + // Set metrics path + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_path"] + target_label = "__metrics_path__" + } + + // Set metrics scraping URL parameters + rule { + action = "labelmap" + regex = "__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_param_(.+)" + replacement = "__param_$1" + } + + // Choose the service port + rule { + source_labels = ["__meta_kubernetes_service_port_name"] + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_portName"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_port_name"] + action = "keepequal" + target_label = "__tmp_port" + } + + rule { + source_labels = ["__meta_kubernetes_service_port_number"] + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_portNumber"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_port_number"] + action = "keepequal" + target_label = "__tmp_port" + } + rule { + action = "labeldrop" + regex = "__tmp_port" + } + + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_scheme"] + regex = "(.+)" + target_label = "__scheme__" + } + + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_scrapeInterval"] + regex = "(.+)" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__scrape_interval__"] + regex = "" + replacement = "60s" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_scrapeTimeout"] + regex = "(.+)" + target_label = "__scrape_timeout__" + } + rule { + source_labels = ["__scrape_timeout__"] + regex = "" + replacement = "10s" + target_label = "__scrape_timeout__" + } + } + + discovery.relabel "annotation_autodiscovery_http" { + targets = array.concat(discovery.relabel.annotation_autodiscovery_pods.output, discovery.relabel.annotation_autodiscovery_services.output) + rule { + source_labels = ["__scheme__"] + regex = "https" + action = "drop" + } + } + + discovery.relabel "annotation_autodiscovery_https" { + targets = array.concat(discovery.relabel.annotation_autodiscovery_pods.output, discovery.relabel.annotation_autodiscovery_services.output) + rule { + source_labels = ["__scheme__"] + regex = "https" + action = "keep" + } + } + + prometheus.scrape "annotation_autodiscovery_http" { + targets = discovery.relabel.annotation_autodiscovery_http.output + honor_labels = true + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + clustering { + enabled = true + } + + forward_to = argument.metrics_destinations.value + } + + prometheus.scrape "annotation_autodiscovery_https" { + targets = discovery.relabel.annotation_autodiscovery_https.output + honor_labels = true + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + tls_config { + insecure_skip_verify = true + } + clustering { + enabled = true + } + + forward_to = argument.metrics_destinations.value + } + } diff --git a/grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/pods_only_test.yaml.snap b/grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/pods_only_test.yaml.snap new file mode 100644 index 0000000..bb8192e --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/pods_only_test.yaml.snap @@ -0,0 +1,221 @@ +will only discover pods: + 1: | + |- + declare "annotation_autodiscovery" { + argument "metrics_destinations" { + comment = "Must be a list of metric destinations where collected metrics should be forwarded to" + } + + discovery.kubernetes "pods" { + role = "pod" + selectors { + role = "pod" + label = "app=myapp" + } + } + + discovery.relabel "annotation_autodiscovery_pods" { + targets = discovery.kubernetes.pods.targets + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_scrape"] + regex = "true" + action = "keep" + } + // Only keep pods that are running, ready, and not init containers. + rule { + source_labels = [ + "__meta_kubernetes_pod_phase", + "__meta_kubernetes_pod_ready", + "__meta_kubernetes_pod_container_init", + ] + regex = "Running;true;false" + action = "keep" + } + rule { + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + rule { + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_job"] + target_label = "job" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_instance"] + target_label = "instance" + } + + // Rules to choose the right container + rule { + source_labels = ["container"] + target_label = "__tmp_container" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_container"] + regex = "(.+)" + target_label = "__tmp_container" + } + rule { + source_labels = ["container"] + action = "keepequal" + target_label = "__tmp_container" + } + rule { + action = "labeldrop" + regex = "__tmp_container" + } + + // Set metrics path + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_path"] + regex = "(.+)" + target_label = "__metrics_path__" + } + + // Set metrics scraping URL parameters + rule { + action = "labelmap" + regex = "__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_param_(.+)" + replacement = "__param_$1" + } + + // Choose the pod port + // The discovery generates a target for each declared container port of the pod. + // If the metricsPortName annotation has value, keep only the target where the port name matches the one of the annotation. + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portName"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + action = "keepequal" + target_label = "__tmp_port" + } + rule { + action = "labeldrop" + regex = "__tmp_port" + } + + // If the metrics port number annotation has a value, override the target address to use it, regardless whether it is + // one of the declared ports on that Pod. + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portNumber", "__meta_kubernetes_pod_ip"] + regex = "(\\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})" + replacement = "[$2]:$1" // IPv6 + target_label = "__address__" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portNumber", "__meta_kubernetes_pod_ip"] + regex = "(\\d+);((([0-9]+?)(\\.|$)){4})" // IPv4, takes priority over IPv6 when both exists + replacement = "$2:$1" + target_label = "__address__" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_scheme"] + regex = "(.+)" + target_label = "__scheme__" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_scrapeInterval"] + regex = "(.+)" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__scrape_interval__"] + regex = "" + replacement = "60s" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_scrapeTimeout"] + regex = "(.+)" + target_label = "__scrape_timeout__" + } + rule { + source_labels = ["__scrape_timeout__"] + regex = "" + replacement = "10s" + target_label = "__scrape_timeout__" + } + rule { + source_labels = ["__meta_kubernetes_pod_label___meta_kubernetes_namespace"] + target_label = "namespace" + } + rule { + target_label = "temp_source" + replacement = "pod" + } + } + + discovery.relabel "annotation_autodiscovery_http" { + targets = array.concat(discovery.relabel.annotation_autodiscovery_pods.output) + rule { + source_labels = ["__scheme__"] + regex = "https" + action = "drop" + } + } + + discovery.relabel "annotation_autodiscovery_https" { + targets = array.concat(discovery.relabel.annotation_autodiscovery_pods.output) + rule { + source_labels = ["__scheme__"] + regex = "https" + action = "keep" + } + } + + prometheus.scrape "annotation_autodiscovery_http" { + targets = discovery.relabel.annotation_autodiscovery_http.output + honor_labels = true + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + clustering { + enabled = true + } + + forward_to = [prometheus.relabel.annotation_autodiscovery.receiver] + } + + prometheus.scrape "annotation_autodiscovery_https" { + targets = discovery.relabel.annotation_autodiscovery_https.output + honor_labels = true + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + tls_config { + insecure_skip_verify = true + } + clustering { + enabled = true + } + + forward_to = [prometheus.relabel.annotation_autodiscovery.receiver] + } + + prometheus.relabel "annotation_autodiscovery" { + max_cache_size = 100000 + rule { + source_labels = ["temp_source"] + regex = "pod" + target_label = "color" + replacement = "blue" + } + rule { + action = "labeldrop" + regex = "temp_source" + } + forward_to = argument.metrics_destinations.value + } + } diff --git a/grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/prometheus_annotation_test.yaml.snap b/grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/prometheus_annotation_test.yaml.snap new file mode 100644 index 0000000..0c876ba --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/prometheus_annotation_test.yaml.snap @@ -0,0 +1,300 @@ +creates a module with default discovery, scraping, and processing configurations: + 1: | + |- + declare "annotation_autodiscovery" { + argument "metrics_destinations" { + comment = "Must be a list of metric destinations where collected metrics should be forwarded to" + } + + discovery.kubernetes "pods" { + role = "pod" + } + + discovery.relabel "annotation_autodiscovery_pods" { + targets = discovery.kubernetes.pods.targets + rule { + source_labels = ["__meta_kubernetes_pod_annotation_prometheus_io_scrape"] + regex = "true" + action = "keep" + } + // Only keep pods that are running, ready, and not init containers. + rule { + source_labels = [ + "__meta_kubernetes_pod_phase", + "__meta_kubernetes_pod_ready", + "__meta_kubernetes_pod_container_init", + ] + regex = "Running;true;false" + action = "keep" + } + rule { + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + rule { + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_job"] + target_label = "job" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_instance"] + target_label = "instance" + } + + // Rules to choose the right container + rule { + source_labels = ["container"] + target_label = "__tmp_container" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_container"] + regex = "(.+)" + target_label = "__tmp_container" + } + rule { + source_labels = ["container"] + action = "keepequal" + target_label = "__tmp_container" + } + rule { + action = "labeldrop" + regex = "__tmp_container" + } + + // Set metrics path + rule { + source_labels = ["__meta_kubernetes_pod_annotation_prometheus_io_path"] + regex = "(.+)" + target_label = "__metrics_path__" + } + + // Set metrics scraping URL parameters + rule { + action = "labelmap" + regex = "__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_param_(.+)" + replacement = "__param_$1" + } + + // Choose the pod port + // The discovery generates a target for each declared container port of the pod. + // If the metricsPortName annotation has value, keep only the target where the port name matches the one of the annotation. + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portName"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + action = "keepequal" + target_label = "__tmp_port" + } + rule { + action = "labeldrop" + regex = "__tmp_port" + } + + // If the metrics port number annotation has a value, override the target address to use it, regardless whether it is + // one of the declared ports on that Pod. + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portNumber", "__meta_kubernetes_pod_ip"] + regex = "(\\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})" + replacement = "[$2]:$1" // IPv6 + target_label = "__address__" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portNumber", "__meta_kubernetes_pod_ip"] + regex = "(\\d+);((([0-9]+?)(\\.|$)){4})" // IPv4, takes priority over IPv6 when both exists + replacement = "$2:$1" + target_label = "__address__" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_prometheus_io_scheme"] + regex = "(.+)" + target_label = "__scheme__" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_scrapeInterval"] + regex = "(.+)" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__scrape_interval__"] + regex = "" + replacement = "60s" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_scrapeTimeout"] + regex = "(.+)" + target_label = "__scrape_timeout__" + } + rule { + source_labels = ["__scrape_timeout__"] + regex = "" + replacement = "10s" + target_label = "__scrape_timeout__" + } + } + + discovery.kubernetes "services" { + role = "service" + } + + discovery.relabel "annotation_autodiscovery_services" { + targets = discovery.kubernetes.services.targets + rule { + source_labels = ["__meta_kubernetes_service_annotation_prometheus_io_scrape"] + regex = "true" + action = "keep" + } + rule { + source_labels = ["__meta_kubernetes_service_name"] + target_label = "service" + } + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_job"] + target_label = "job" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_instance"] + target_label = "instance" + } + + // Set metrics path + rule { + source_labels = ["__meta_kubernetes_service_annotation_prometheus_io_path"] + target_label = "__metrics_path__" + } + + // Set metrics scraping URL parameters + rule { + action = "labelmap" + regex = "__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_param_(.+)" + replacement = "__param_$1" + } + + // Choose the service port + rule { + source_labels = ["__meta_kubernetes_service_port_name"] + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_portName"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_port_name"] + action = "keepequal" + target_label = "__tmp_port" + } + + rule { + source_labels = ["__meta_kubernetes_service_port_number"] + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_portNumber"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_port_number"] + action = "keepequal" + target_label = "__tmp_port" + } + rule { + action = "labeldrop" + regex = "__tmp_port" + } + + rule { + source_labels = ["__meta_kubernetes_service_annotation_prometheus_io_scheme"] + regex = "(.+)" + target_label = "__scheme__" + } + + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_scrapeInterval"] + regex = "(.+)" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__scrape_interval__"] + regex = "" + replacement = "60s" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_scrapeTimeout"] + regex = "(.+)" + target_label = "__scrape_timeout__" + } + rule { + source_labels = ["__scrape_timeout__"] + regex = "" + replacement = "10s" + target_label = "__scrape_timeout__" + } + } + + discovery.relabel "annotation_autodiscovery_http" { + targets = array.concat(discovery.relabel.annotation_autodiscovery_pods.output, discovery.relabel.annotation_autodiscovery_services.output) + rule { + source_labels = ["__scheme__"] + regex = "https" + action = "drop" + } + } + + discovery.relabel "annotation_autodiscovery_https" { + targets = array.concat(discovery.relabel.annotation_autodiscovery_pods.output, discovery.relabel.annotation_autodiscovery_services.output) + rule { + source_labels = ["__scheme__"] + regex = "https" + action = "keep" + } + } + + prometheus.scrape "annotation_autodiscovery_http" { + targets = discovery.relabel.annotation_autodiscovery_http.output + honor_labels = true + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + clustering { + enabled = true + } + + forward_to = argument.metrics_destinations.value + } + + prometheus.scrape "annotation_autodiscovery_https" { + targets = discovery.relabel.annotation_autodiscovery_https.output + honor_labels = true + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + tls_config { + insecure_skip_verify = true + } + clustering { + enabled = true + } + + forward_to = argument.metrics_destinations.value + } + } diff --git a/grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/selectors_test.yaml.snap b/grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/selectors_test.yaml.snap new file mode 100644 index 0000000..1f2965e --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/tests/__snapshot__/selectors_test.yaml.snap @@ -0,0 +1,308 @@ +will set appropriate selectors: + 1: | + |- + declare "annotation_autodiscovery" { + argument "metrics_destinations" { + comment = "Must be a list of metric destinations where collected metrics should be forwarded to" + } + + discovery.kubernetes "pods" { + role = "pod" + selectors { + role = "pod" + label = "app=myapp,color=blue" + } + } + + discovery.relabel "annotation_autodiscovery_pods" { + targets = discovery.kubernetes.pods.targets + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_scrape"] + regex = "true" + action = "keep" + } + // Only keep pods that are running, ready, and not init containers. + rule { + source_labels = [ + "__meta_kubernetes_pod_phase", + "__meta_kubernetes_pod_ready", + "__meta_kubernetes_pod_container_init", + ] + regex = "Running;true;false" + action = "keep" + } + rule { + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + rule { + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_job"] + target_label = "job" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_instance"] + target_label = "instance" + } + + // Rules to choose the right container + rule { + source_labels = ["container"] + target_label = "__tmp_container" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_container"] + regex = "(.+)" + target_label = "__tmp_container" + } + rule { + source_labels = ["container"] + action = "keepequal" + target_label = "__tmp_container" + } + rule { + action = "labeldrop" + regex = "__tmp_container" + } + + // Set metrics path + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_path"] + regex = "(.+)" + target_label = "__metrics_path__" + } + + // Set metrics scraping URL parameters + rule { + action = "labelmap" + regex = "__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_param_(.+)" + replacement = "__param_$1" + } + + // Choose the pod port + // The discovery generates a target for each declared container port of the pod. + // If the metricsPortName annotation has value, keep only the target where the port name matches the one of the annotation. + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portName"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + action = "keepequal" + target_label = "__tmp_port" + } + rule { + action = "labeldrop" + regex = "__tmp_port" + } + + // If the metrics port number annotation has a value, override the target address to use it, regardless whether it is + // one of the declared ports on that Pod. + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portNumber", "__meta_kubernetes_pod_ip"] + regex = "(\\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})" + replacement = "[$2]:$1" // IPv6 + target_label = "__address__" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_portNumber", "__meta_kubernetes_pod_ip"] + regex = "(\\d+);((([0-9]+?)(\\.|$)){4})" // IPv4, takes priority over IPv6 when both exists + replacement = "$2:$1" + target_label = "__address__" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_scheme"] + regex = "(.+)" + target_label = "__scheme__" + } + + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_scrapeInterval"] + regex = "(.+)" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__scrape_interval__"] + regex = "" + replacement = "60s" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__meta_kubernetes_pod_annotation_k8s_grafana_com_metrics_scrapeTimeout"] + regex = "(.+)" + target_label = "__scrape_timeout__" + } + rule { + source_labels = ["__scrape_timeout__"] + regex = "" + replacement = "10s" + target_label = "__scrape_timeout__" + } + } + + discovery.kubernetes "services" { + role = "service" + selectors { + role = "service" + label = "app=myapp,region in (north,east)" + } + } + + discovery.relabel "annotation_autodiscovery_services" { + targets = discovery.kubernetes.services.targets + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_scrape"] + regex = "true" + action = "keep" + } + rule { + source_labels = ["__meta_kubernetes_service_name"] + target_label = "service" + } + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_job"] + target_label = "job" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_instance"] + target_label = "instance" + } + + // Set metrics path + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_path"] + target_label = "__metrics_path__" + } + + // Set metrics scraping URL parameters + rule { + action = "labelmap" + regex = "__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_param_(.+)" + replacement = "__param_$1" + } + + // Choose the service port + rule { + source_labels = ["__meta_kubernetes_service_port_name"] + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_portName"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_port_name"] + action = "keepequal" + target_label = "__tmp_port" + } + + rule { + source_labels = ["__meta_kubernetes_service_port_number"] + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_portNumber"] + regex = "(.+)" + target_label = "__tmp_port" + } + rule { + source_labels = ["__meta_kubernetes_service_port_number"] + action = "keepequal" + target_label = "__tmp_port" + } + rule { + action = "labeldrop" + regex = "__tmp_port" + } + + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_scheme"] + regex = "(.+)" + target_label = "__scheme__" + } + + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_scrapeInterval"] + regex = "(.+)" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__scrape_interval__"] + regex = "" + replacement = "60s" + target_label = "__scrape_interval__" + } + rule { + source_labels = ["__meta_kubernetes_service_annotation_k8s_grafana_com_metrics_scrapeTimeout"] + regex = "(.+)" + target_label = "__scrape_timeout__" + } + rule { + source_labels = ["__scrape_timeout__"] + regex = "" + replacement = "10s" + target_label = "__scrape_timeout__" + } + } + + discovery.relabel "annotation_autodiscovery_http" { + targets = array.concat(discovery.relabel.annotation_autodiscovery_pods.output, discovery.relabel.annotation_autodiscovery_services.output) + rule { + source_labels = ["__scheme__"] + regex = "https" + action = "drop" + } + } + + discovery.relabel "annotation_autodiscovery_https" { + targets = array.concat(discovery.relabel.annotation_autodiscovery_pods.output, discovery.relabel.annotation_autodiscovery_services.output) + rule { + source_labels = ["__scheme__"] + regex = "https" + action = "keep" + } + } + + prometheus.scrape "annotation_autodiscovery_http" { + targets = discovery.relabel.annotation_autodiscovery_http.output + honor_labels = true + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + clustering { + enabled = true + } + + forward_to = argument.metrics_destinations.value + } + + prometheus.scrape "annotation_autodiscovery_https" { + targets = discovery.relabel.annotation_autodiscovery_https.output + honor_labels = true + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + tls_config { + insecure_skip_verify = true + } + clustering { + enabled = true + } + + forward_to = argument.metrics_destinations.value + } + } diff --git a/grafana/charts/feature-annotation-autodiscovery/tests/default_test.yaml b/grafana/charts/feature-annotation-autodiscovery/tests/default_test.yaml new file mode 100644 index 0000000..eca5280 --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/tests/default_test.yaml @@ -0,0 +1,13 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test default values +templates: + - configmap.yaml +tests: + - it: creates a module with default discovery, scraping, and processing configurations + set: + deployAsConfigMap: true + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] diff --git a/grafana/charts/feature-annotation-autodiscovery/tests/namespaced_test.yaml b/grafana/charts/feature-annotation-autodiscovery/tests/namespaced_test.yaml new file mode 100644 index 0000000..e18989f --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/tests/namespaced_test.yaml @@ -0,0 +1,23 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test default values +templates: + - configmap.yaml +tests: + - it: can use a specified list of namespaces + set: + deployAsConfigMap: true + namespaces: ["a", "b"] + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] + - it: can exclude a specified list of namespaces + set: + deployAsConfigMap: true + excludeNamespaces: ["a", "b"] + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] diff --git a/grafana/charts/feature-annotation-autodiscovery/tests/pods_only_test.yaml b/grafana/charts/feature-annotation-autodiscovery/tests/pods_only_test.yaml new file mode 100644 index 0000000..f4322fb --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/tests/pods_only_test.yaml @@ -0,0 +1,23 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test Pods only +templates: + - configmap.yaml +tests: + - it: will only discover pods + set: + deployAsConfigMap: true + labelSelectors: + app: myapp + pods: + enabled: true + labels: + namespace: __meta_kubernetes_namespace + staticLabels: + color: blue + services: + enabled: false + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] diff --git a/grafana/charts/feature-annotation-autodiscovery/tests/prometheus_annotation_test.yaml b/grafana/charts/feature-annotation-autodiscovery/tests/prometheus_annotation_test.yaml new file mode 100644 index 0000000..3e356f8 --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/tests/prometheus_annotation_test.yaml @@ -0,0 +1,18 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test with prometheus.io annotations +templates: + - configmap.yaml +tests: + - it: creates a module with default discovery, scraping, and processing configurations + set: + deployAsConfigMap: true + annotations: + scrape: prometheus.io/scrape + metricsScheme: prometheus.io/scheme + metricsPath: prometheus.io/path + metricsPort: prometheus.io/port + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] diff --git a/grafana/charts/feature-annotation-autodiscovery/tests/selectors_test.yaml b/grafana/charts/feature-annotation-autodiscovery/tests/selectors_test.yaml new file mode 100644 index 0000000..4f58496 --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/tests/selectors_test.yaml @@ -0,0 +1,23 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test selectors +templates: + - configmap.yaml +tests: + - it: will set appropriate selectors + set: + deployAsConfigMap: true + labelSelectors: + app: myapp + pods: + labelSelectors: + color: blue + services: + labelSelectors: + region: + - north + - east + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] diff --git a/grafana/charts/feature-annotation-autodiscovery/values.schema.json b/grafana/charts/feature-annotation-autodiscovery/values.schema.json new file mode 100644 index 0000000..b8af1ca --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/values.schema.json @@ -0,0 +1,153 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "annotations": { + "type": "object", + "properties": { + "instance": { + "type": "string" + }, + "job": { + "type": "string" + }, + "metricsContainer": { + "type": "string" + }, + "metricsParam": { + "type": "string" + }, + "metricsPath": { + "type": "string" + }, + "metricsPortName": { + "type": "string" + }, + "metricsPortNumber": { + "type": "string" + }, + "metricsScheme": { + "type": "string" + }, + "metricsScrapeInterval": { + "type": "string" + }, + "metricsScrapeTimeout": { + "type": "string" + }, + "scrape": { + "type": "string" + } + } + }, + "bearerToken": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "token": { + "type": "string" + } + } + }, + "deployAsConfigMap": { + "type": "boolean" + }, + "excludeNamespaces": { + "type": "array" + }, + "extraDiscoveryRules": { + "type": "string" + }, + "extraMetricProcessingRules": { + "type": "string" + }, + "fullnameOverride": { + "type": "string" + }, + "global": { + "type": "object", + "properties": { + "maxCacheSize": { + "type": "integer" + }, + "scrapeInterval": { + "type": "string" + }, + "scrapeTimeout": { + "type": "string" + } + } + }, + "labelSelectors": { + "type": "object" + }, + "maxCacheSize": { + "type": "null" + }, + "metricsTuning": { + "type": "object", + "properties": { + "excludeMetrics": { + "type": "array" + }, + "includeMetrics": { + "type": "array" + } + } + }, + "nameOverride": { + "type": "string" + }, + "namespaces": { + "type": "array" + }, + "pods": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "labelSelectors": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "staticLabels": { + "type": "object" + }, + "staticLabelsFrom": { + "type": "object" + } + } + }, + "scrapeInterval": { + "type": "string" + }, + "scrapeTimeout": { + "type": "string" + }, + "services": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "labelSelectors": { + "type": "object" + }, + "labels": { + "type": "object" + }, + "staticLabels": { + "type": "object" + }, + "staticLabelsFrom": { + "type": "object" + } + } + } + } +} diff --git a/grafana/charts/feature-annotation-autodiscovery/values.yaml b/grafana/charts/feature-annotation-autodiscovery/values.yaml new file mode 100644 index 0000000..fe1363b --- /dev/null +++ b/grafana/charts/feature-annotation-autodiscovery/values.yaml @@ -0,0 +1,178 @@ +--- +# -- Name override +# @section -- General settings +nameOverride: "" + +# -- Full name override +# @section -- General settings +fullnameOverride: "" + +global: + # -- How frequently to scrape metrics. + # @section -- Global Settings + scrapeInterval: 60s + + # -- The scrape timeout for discovered pods and services. + # @section -- Global Settings + scrapeTimeout: 10s + + # -- Sets the max_cache_size for every prometheus.relabel component. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) + # This should be at least 2x-5x your largest scrape target or samples appended rate. + # @section -- Global Settings + maxCacheSize: 100000 + +# Annotations that are used to discover and configure metric scraping targets. Add these annotations +# to your services or pods to control how autodiscovery will find and scrape metrics from your service or pod. +annotations: + # -- Annotation for enabling scraping for this service or pod. Value should be either "true" or "false" + # @section -- Annotations + scrape: "k8s.grafana.com/scrape" + # -- Annotation for overriding the job label + # @section -- Annotations + job: "k8s.grafana.com/job" + # -- Annotation for overriding the instance label + # @section -- Annotations + instance: "k8s.grafana.com/instance" + # -- Annotation for selecting the specific container to scrape. + # @section -- Annotations + metricsContainer: "k8s.grafana.com/metrics.container" + # -- Annotation for setting or overriding the metrics path. If not set, it defaults to /metrics + # @section -- Annotations + metricsPath: "k8s.grafana.com/metrics.path" + # -- Annotation for setting the metrics port by name. + # @section -- Annotations + metricsPortName: "k8s.grafana.com/metrics.portName" + # -- Annotation for setting the metrics port by number. + # @section -- Annotations + metricsPortNumber: "k8s.grafana.com/metrics.portNumber" + # -- Annotation for setting the metrics scheme, default: http. + # @section -- Annotations + metricsScheme: "k8s.grafana.com/metrics.scheme" + # -- Annotation for setting `__param_` parameters when scraping. + # Example: `k8s.grafana.com/metrics.param_key: "value"`. + # @section -- Annotations + metricsParam: "k8s.grafana.com/metrics.param" + # -- Annotation for overriding the scrape interval for this service or pod. Value should be a duration like "15s, 1m". + # Overrides metrics.autoDiscover.scrapeInterval + # @section -- Annotations + metricsScrapeInterval: "k8s.grafana.com/metrics.scrapeInterval" + # -- Annotation for overriding the scrape timeout for this service or pod. Value should be a duration like "15s, 1m". + # Overrides metrics.autoDiscover.scrapeTimeout + # @section -- Annotations + metricsScrapeTimeout: "k8s.grafana.com/metrics.scrapeTimeout" + +# -- The list of namespaces to include in autodiscovery. If empty, all namespaces are included. +# @section -- Discovery Settings +namespaces: [] + +# -- The list of namespaces to exclude from autodiscovery. +# @section -- Discovery Settings +excludeNamespaces: [] + +# -- Filter the list of discovered pods and services by labels. +# Example: `labelSelectors: { 'app': 'myapp' }` will only discover pods and services with the label `app=myapp`. +# Example: `labelSelectors: { 'app': ['myapp', 'myotherapp'] }` will only discover pods and services with the label `app=myapp` or `app=myotherapp`. +# @section -- Discovery Settings +labelSelectors: {} + +pods: + # -- Enable discovering Pods with annotations. + # @section -- Pod Discovery Settings + enabled: true + + # -- Filter the list of discovered Pods by labels. + # Example: `labelSelectors: { 'app': 'myapp' }` will only discover Pods with the label `app=myapp`. + # Example: `labelSelectors: { 'app': ['myapp', 'myotherapp'] }` will only discover Pods with the label `app=myapp` or `app=myotherapp`. + # @section -- Pod Discovery Settings + labelSelectors: {} + + # -- Add labels to metrics from discovered Pods. Runs during discovery, so __meta_ labels are available. See the + # [documentation](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.kubernetes/#pod-role) + # for the full list of meta labels. + # @section -- Pod Metric Processing Settings + labels: {} + + # -- Metric labels to set with static data for discovered Pods. + # @section -- Pod Metric Processing Settings + staticLabels: {} + + # -- Static labels to set on metrics from discovered Pods, not quoted so it can reference config components. + # @section -- Pod Metric Processing Settings + staticLabelsFrom: {} + +services: + # -- Enable discovering Services with annotations. + # @section -- Services + enabled: true + + # -- Filter the list of discovered Services by labels. + # Example: `labelSelectors: { 'app': 'myapp' }` will only discover Services with the label `app=myapp`. + # Example: `labelSelectors: { 'app': ['myapp', 'myotherapp'] }` will only discover Services with the label `app=myapp` or `app=myotherapp`. + # @section -- Service Discovery Settings + labelSelectors: {} + + # -- Add labels to metrics from discovered Services. Run during discovery, so __meta_ labels are available. See the + # [documentation](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.kubernetes/#service-role) + # for the full list of meta labels. + # @section -- Service Metric Processing Settings + labels: {} + + # -- Metric labels to set with static data for discovered Services. + # @section -- Service Metric Processing Settings + staticLabels: {} + + # -- Static labels to set on metrics from discovered Services, not quoted so it can reference config components. + # @section -- Service Metric Processing Settings + staticLabelsFrom: {} + +# -- Rule blocks to be added to the discovery.relabel component for discovered pods and services. +# These relabeling rules are applied pre-scrape against the targets from service discovery. +# Before the scrape, any remaining target labels that start with `__` (i.e. `__meta_kubernetes*`) are dropped. +# ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) +# @section -- Discovery Settings +extraDiscoveryRules: "" + +# -- How frequently to scrape metrics from discovered pods and services. Only used if the `k8s.grafana.com/metrics.scrapeInterval` annotation is not set. +# Overrides global.scrapeInterval +# @default -- 60s +# @section -- Scrape Settings +scrapeInterval: "" + +# -- The scrape timeout for discovered pods and services. Only used if the `k8s.grafana.com/metrics.scrapeTimeout` annotation is not set. +# Overrides global.scrapeTimeout +# @default -- 10s +# @section -- Scrape Settings +scrapeTimeout: "" + +# Adjustments to the scraped metrics to filter the amount of metrics sent to storage. +# @section -- Metric Processing Settings +metricsTuning: + # -- Metrics to keep. Can use regular expressions. + # @section -- Metric Processing Settings + includeMetrics: [] + # -- Metrics to drop. Can use regular expressions. + # @section -- Metric Processing Settings + excludeMetrics: [] + +# -- Rule blocks to be added to the prometheus.relabel component for discovered pods and services. +# These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no `__meta*` labels are present. +# ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#rule-block)) +# @section -- Metric Processing Settings +extraMetricProcessingRules: "" + +# -- Sets the max_cache_size for cadvisor prometheus.relabel component. +# This should be at least 2x-5x your largest scrape target or samples appended rate. +# ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) +# Overrides global.maxCacheSize +# @raw +# @section -- Metric Processing Settings +maxCacheSize: + +# -- Sets bearer_token_file line in the prometheus.scrape annotation_autodiscovery. +# @section -- Scrape Settings +bearerToken: + enabled: true + token: /var/run/secrets/kubernetes.io/serviceaccount/token + +# @ignore +deployAsConfigMap: false diff --git a/grafana/charts/feature-application-observability/.helmignore b/grafana/charts/feature-application-observability/.helmignore new file mode 100644 index 0000000..2b29eaf --- /dev/null +++ b/grafana/charts/feature-application-observability/.helmignore @@ -0,0 +1,6 @@ +docs +schema-mods +tests +Makefile +README.md +README.md.gotmpl diff --git a/grafana/charts/feature-application-observability/Chart.lock b/grafana/charts/feature-application-observability/Chart.lock new file mode 100644 index 0000000..e39a95f --- /dev/null +++ b/grafana/charts/feature-application-observability/Chart.lock @@ -0,0 +1,3 @@ +dependencies: [] +digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726 +generated: "2024-09-25T13:46:10.334192-05:00" diff --git a/grafana/charts/feature-application-observability/Chart.yaml b/grafana/charts/feature-application-observability/Chart.yaml new file mode 100644 index 0000000..74a2b06 --- /dev/null +++ b/grafana/charts/feature-application-observability/Chart.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: v2 +name: feature-application-observability +description: Gathers application data +icon: https://raw.githubusercontent.com/grafana/grafana/main/public/img/grafana_icon.svg +sources: + - https://github.com/grafana/k8s-monitoring-helm/tree/main/charts/k8s-monitoring/charts/feature-application-observability +version: 1.0.0 +appVersion: 1.0.0 +maintainers: + - email: pete.wall@grafana.com + name: petewall +dependencies: [] diff --git a/grafana/charts/feature-application-observability/Makefile b/grafana/charts/feature-application-observability/Makefile new file mode 100644 index 0000000..107caf8 --- /dev/null +++ b/grafana/charts/feature-application-observability/Makefile @@ -0,0 +1,34 @@ +HAS_HELM_DOCS := $(shell command -v helm-docs;) +HAS_HELM_UNITTEST := $(shell helm plugin list | grep unittest 2> /dev/null) + +.SECONDEXPANSION: +README.md: values.yaml Chart.yaml $$(wildcard README.md.gotmpl) +ifdef HAS_HELM_DOCS + helm-docs +else + docker run --rm --volume "$(shell pwd):/helm-docs" -u $(shell id -u) jnorwood/helm-docs:latest +endif + +Chart.lock: Chart.yaml + helm dependency update . + @touch Chart.lock # Ensure the timestamp is updated + +values.schema.json: values.yaml $$(wildcard schema-mods/*) + ../../../../scripts/schema-gen.sh . + +.PHONY: clean +clean: + rm -f README.md values.schema.json + +.PHONY: build +build: README.md Chart.lock values.schema.json + +.PHONY: test +test: build + helm lint . + ct lint --lint-conf ../../../../.configs/lintconf.yaml --helm-dependency-extra-args=--skip-refresh --charts . +ifdef HAS_HELM_UNITTEST + helm unittest . +else + docker run --rm --volume $(shell pwd):/apps helmunittest/helm-unittest:3.17.0-0.7.1 . +endif diff --git a/grafana/charts/feature-application-observability/README.md b/grafana/charts/feature-application-observability/README.md new file mode 100644 index 0000000..1a4f07a --- /dev/null +++ b/grafana/charts/feature-application-observability/README.md @@ -0,0 +1,179 @@ + + +# feature-application-observability + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) +Gathers application data + +The Application Observability feature enables the collection of application telemetry data. + +## Before enabling + +Before you enable this feature, you must enable one or more receivers where data will be sent from the application. + +## Testing + +This chart contains unit tests to verify the generated configuration. The hidden value `deployAsConfigMap` will render +the generated configuration into a ConfigMap object. While this ConfigMap is not used during regular operation, you can +use it to show the outcome of a given values file. + +The unit tests use this ConfigMap to create an object with the configuration that can be asserted against. To run the +tests, use `helm test`. + +Be sure perform actual integration testing in a live environment in the main [k8s-monitoring](../..) chart. + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| petewall | | | + + +## Source Code + +* + + + + +## Values + +### Connectors: Grafana Cloud Host Info + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| connectors.grafanaCloudMetrics.enabled | bool | `true` | Generate host info metrics from telemetry data. These metrics are required for using Application Observability in Grafana Cloud. Note: Enabling this may incur additional costs. See [Application Observability Pricing](https://grafana.com/docs/grafana-cloud/monitor-applications/application-observability/pricing/) | + +### Connectors: Span Logs + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| connectors.spanLogs.enabled | bool | `false` | Use a span logs connector which creates logs from spans. | +| connectors.spanLogs.labels | list | `[]` | A list of keys that will be logged as labels. | +| connectors.spanLogs.process | bool | `false` | Log one line for every process. | +| connectors.spanLogs.processAttributes | list | `[]` | Additional process attributes to log. | +| connectors.spanLogs.roots | bool | `false` | Log one line for every root span of a trace. | +| connectors.spanLogs.spanAttributes | list | `[]` | Additional span attributes to log. | +| connectors.spanLogs.spans | bool | `false` | Create a log line for each span. This can lead to a large number of logs. | + +### Connectors: Span Metrics + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| connectors.spanMetrics.dimensions | list | `[]` | Define dimensions to be added. Some are set internally by default: [service.name, span.name, span.kind, status.code] Example: - name: "http.status_code" - name: "http.method" default: "GET" | +| connectors.spanMetrics.dimensionsCacheSize | int | `1000` | How many dimensions to cache | +| connectors.spanMetrics.enabled | bool | `false` | Use a span metrics connector which creates metrics from spans. | +| connectors.spanMetrics.events.enabled | bool | `false` | Capture events metrics, which track span events. | +| connectors.spanMetrics.exemplars.enabled | bool | `false` | Attach exemplars to histograms. | +| connectors.spanMetrics.exemplars.maxPerDataPoint | number | `nil` | Limits the number of exemplars that can be added to a unique dimension set. | +| connectors.spanMetrics.histogram.enabled | bool | `true` | Capture histogram metrics, derived from spans’ durations. | +| connectors.spanMetrics.histogram.explicit.buckets | list | `["2ms","4ms","6ms","8ms","10ms","50ms","100ms","200ms","400ms","800ms","1s","1400ms","2s","5s","10s","15s"]` | The histogram buckets to use. | +| connectors.spanMetrics.histogram.exponential.maxSize | int | `160` | Maximum number of buckets per positive or negative number range. | +| connectors.spanMetrics.histogram.type | string | `"explicit"` | Type of histograms to create. Must be either "explicit" or "exponential". | +| connectors.spanMetrics.histogram.unit | string | `"ms"` | The histogram unit. | +| connectors.spanMetrics.namespace | string | `"traces.span.metrics"` | The Metric namespace. | + +### General settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| fullnameOverride | string | `""` | Full name override | +| nameOverride | string | `""` | Name override | + +### Processors: Batch + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| processors.batch.maxSize | int | `0` | The upper limit of the amount of data contained in a single batch. When set to 0, batches can be any size. | +| processors.batch.size | int | `8192` | What batch size to use | +| processors.batch.timeout | string | `"2s"` | How long before sending (Processors) | + +### Processors: Interval + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| processors.interval.enabled | bool | `false` | Utilize an interval processor to aggregate metrics and periodically forward the latest values to the next component in the pipeline. | +| processors.interval.interval | string | `"60s"` | The interval at which to emit aggregated metrics. | +| processors.interval.passthrough.gauge | bool | `false` | Determines whether gauge metrics should be passed through as they are or aggregated. | +| processors.interval.passthrough.summary | bool | `false` | Determines whether summary metrics should be passed through as they are or aggregated. | + +### Processors: K8s Attributes + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| processors.k8sattributes.annotations | list | `[]` | Kubernetes annotations to extract and add to the attributes of the received telemetry data. | +| processors.k8sattributes.labels | list | `[]` | Kubernetes labels to extract and add to the attributes of the received telemetry data. | +| processors.k8sattributes.metadata | list | `["k8s.namespace.name","k8s.pod.name","k8s.deployment.name","k8s.statefulset.name","k8s.daemonset.name","k8s.cronjob.name","k8s.job.name","k8s.node.name","k8s.pod.uid","k8s.pod.start_time"]` | Kubernetes metadata to extract and add to the attributes of the received telemetry data. | + +### Processors: Memory Limiter + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| processors.memoryLimiter.checkInterval | string | `"1s"` | How often to check memory usage. | +| processors.memoryLimiter.enabled | bool | `false` | Use a memory limiter. | +| processors.memoryLimiter.limit | string | `"0MiB"` | Maximum amount of memory targeted to be allocated by the process heap. | + +### Processors: Resource Detection + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| processors.resourceDetection.env.enabled | bool | `true` | Enable getting resource attributes from the OTEL_RESOURCE_ATTRIBUTES environment variable. | +| processors.resourceDetection.kubernetesNode.authType | string | `"serviceAccount"` | The authentication method. This should not be changed. | +| processors.resourceDetection.kubernetesNode.enabled | bool | `false` | Enable getting resource attributes about the Kubernetes node from the API server. | +| processors.resourceDetection.kubernetesNode.nodeFromEnvVar | string | `"K8S_NODE_NAME"` | The name of an environment variable from which to retrieve the node name. | +| processors.resourceDetection.override | bool | `true` | Configures whether existing resource attributes should be overridden or preserved. | +| processors.resourceDetection.system.enabled | bool | `true` | Enable getting resource attributes from the host machine. | +| processors.resourceDetection.system.hostnameSources | list | `["os"]` | The priority list of sources from which the hostname will be determined. Options: ["dns", "os", "cname", "lookup"]. | +| processors.resourceDetection.system.resourceAttributes | object | `{}` | The list of resource attributes to add for system resource detection. See the [Alloy documentation](https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.resourcedetection/#system--resource_attributes) for a list of available attributes. | + +### Receivers: Jaeger + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| receivers.jaeger.grpc | object | `{"enabled":false,"port":14250}` | Configuration for the Jaeger receiver using the gRPC protocol. | +| receivers.jaeger.includeDebugMetrics | bool | `false` | Whether to include high-cardinality debug metrics. | +| receivers.jaeger.thriftBinary | object | `{"enabled":false,"port":6832}` | Configuration for the Jaeger receiver using the Thrift binary protocol. | +| receivers.jaeger.thriftCompact | object | `{"enabled":false,"port":6831}` | Configuration for the Jaeger receiver using the Thrift compact protocol. | +| receivers.jaeger.thriftHttp | object | `{"enabled":false,"port":14268}` | Configuration for the Jaeger receiver using the Thrift HTTP protocol. | + +### Receivers: OTLP + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| receivers.otlp.grpc.enabled | bool | `false` | Accept application data over OTLP gRPC. | +| receivers.otlp.grpc.maxConcurrentStreams | int | `0` | Limit the number of concurrent streaming gRPC calls. 0 means no limit. | +| receivers.otlp.grpc.maxReceivedMessageSize | string | `"4MiB"` | Maximum size of messages the gRPC server will accept. | +| receivers.otlp.grpc.port | int | `4317` | The port to listen on for OTLP gRPC requests. | +| receivers.otlp.grpc.readBufferSize | string | `"512KiB"` | Size of the read buffer the gRPC server will use for reading from clients. | +| receivers.otlp.grpc.writeBufferSize | string | `"32KiB"` | Size of the write buffer the gRPC server will use for writing to clients. | +| receivers.otlp.http.enabled | bool | `false` | Accept application data over OTLP HTTP. | +| receivers.otlp.http.maxRequestBodySize | string | `"20MiB"` | Maximum request body size the server will allow. | +| receivers.otlp.http.port | int | `4318` | The port to listen on for OTLP HTTP requests. | +| receivers.otlp.includeDebugMetrics | bool | `false` | Whether to include high-cardinality debug metrics. | + +### Receivers: Zipkin + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| receivers.zipkin | object | `{"enabled":false,"includeDebugMetrics":false,"port":9411}` | The Zipkin receiver configuration. | +| receivers.zipkin.includeDebugMetrics | bool | `false` | Whether to include high-cardinality debug metrics. | + +### Other Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| logs.enabled | bool | `true` | | +| logs.filters | object | `{"log_record":[]}` | Apply a filter to logs received via receivers. ([docs](https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.filter/)) | +| logs.transforms | object | `{"labels":["cluster","namespace","job","pod"],"log":[],"resource":[]}` | Apply a transformation to logs received via the OTLP or OTLP HTTP receivers. ([docs](https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.transform/)) | +| logs.transforms.labels | list | `["cluster","namespace","job","pod"]` | The list of labels to set in the log stream. | +| logs.transforms.log | list | `[]` | Log transformation rules. | +| logs.transforms.resource | list | `[]` | Resource transformation rules. | +| metrics.enabled | bool | `true` | | +| metrics.filters | object | `{"datapoint":[],"metric":[]}` | Apply a filter to metrics received via the OTLP or OTLP HTTP receivers. ([docs](https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.filter/)) | +| metrics.transforms | object | `{"datapoint":[],"metric":[],"resource":[]}` | Apply a transformation to metrics received via the OTLP or OTLP HTTP receivers. ([docs](https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.transform/)) | +| traces.enabled | bool | `true` | | +| traces.filters | object | `{"span":[],"spanevent":[]}` | Apply a filter to traces received via the OTLP or OTLP HTTP receivers. ([docs](https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.filter/)) | +| traces.transforms | object | `{"resource":[],"span":[],"spanevent":[]}` | Apply a transformation to traces received via the OTLP or OTLP HTTP receivers. ([docs](https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.transform/)) | diff --git a/grafana/charts/feature-application-observability/README.md.gotmpl b/grafana/charts/feature-application-observability/README.md.gotmpl new file mode 100644 index 0000000..c3c21d4 --- /dev/null +++ b/grafana/charts/feature-application-observability/README.md.gotmpl @@ -0,0 +1,37 @@ + + +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} +{{ template "chart.badgesSection" . }} +{{ template "chart.description" . }} +{{ template "chart.homepageLine" . }} + +The Application Observability feature enables the collection of application telemetry data. + +## Before enabling + +Before you enable this feature, you must enable one or more receivers where data will be sent from the application. + +## Testing + +This chart contains unit tests to verify the generated configuration. The hidden value `deployAsConfigMap` will render +the generated configuration into a ConfigMap object. While this ConfigMap is not used during regular operation, you can +use it to show the outcome of a given values file. + +The unit tests use this ConfigMap to create an object with the configuration that can be asserted against. To run the +tests, use `helm test`. + +Be sure perform actual integration testing in a live environment in the main [k8s-monitoring](../..) chart. + +{{ template "chart.maintainersSection" . }} + + +{{ template "chart.sourcesSection" . }} + + +{{ template "chart.requirementsSection" . }} + +{{ template "chart.valuesSection" . }} diff --git a/grafana/charts/feature-application-observability/schema-mods/types-and-enums.json b/grafana/charts/feature-application-observability/schema-mods/types-and-enums.json new file mode 100644 index 0000000..6f21856 --- /dev/null +++ b/grafana/charts/feature-application-observability/schema-mods/types-and-enums.json @@ -0,0 +1,13 @@ +{ + "properties": { + "connectors": { + "properties": { + "spanMetrics": { + "properties": { + "histogram": {"properties": {"type": {"enum": ["explicit", "exponential"]}}} + } + } + } + } + } +} diff --git a/grafana/charts/feature-application-observability/templates/_connector_host_info.tpl b/grafana/charts/feature-application-observability/templates/_connector_host_info.tpl new file mode 100644 index 0000000..5c646d5 --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_connector_host_info.tpl @@ -0,0 +1,14 @@ +{{/* Inputs: Values (values) metricsOutput, name */}} +{{/* https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.connector.host_info/ */}} +{{- define "feature.applicationObservability.connector.host_info.alloy.target" }}otelcol.connector.host_info.{{ .name | default "default" }}.input{{- end }} +{{- define "feature.applicationObservability.connector.host_info.alloy" }} +otelcol.connector.host_info "{{ .name | default "default" }}" { + host_identifiers = [ "k8s.node.name" ] + + output { +{{- if and .metrics .Values.metrics.enabled }} + metrics = {{ .metrics }} +{{- end }} + } +} +{{- end }} \ No newline at end of file diff --git a/grafana/charts/feature-application-observability/templates/_connector_span_logs.tpl b/grafana/charts/feature-application-observability/templates/_connector_span_logs.tpl new file mode 100644 index 0000000..01eb343 --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_connector_span_logs.tpl @@ -0,0 +1,31 @@ +{{/* Inputs: Values (values) metricsOutput, name */}} +{{/* https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.connector.spanlogs/ */}} +{{- define "feature.applicationObservability.connector.spanlogs.alloy.target" }}otelcol.connector.spanlogs.{{ .name | default "default" }}.input{{- end }} +{{- define "feature.applicationObservability.connector.spanlogs.alloy" }} +otelcol.connector.spanlogs "{{ .name | default "default" }}" { +{{- if .Values.connectors.spanLogs.spans }} + spans = true +{{- end }} +{{- if .Values.connectors.spanLogs.spansAttributes }} + spans_attributes = {{ .Values.connectors.spanLogs.spansAttributes | toJson }} +{{- end }} +{{- if .Values.connectors.spanLogs.roots }} + roots = true +{{- end }} +{{- if .Values.connectors.spanLogs.process }} + process = true +{{- end }} +{{- if .Values.connectors.spanLogs.processAttributes }} + process_attributes = {{ .Values.connectors.spanLogs.processAttributes | toJson }} +{{- end }} +{{- if .Values.connectors.spanLogs.labels }} + labels = {{ .Values.connectors.spanLogs.labels | toJson }} +{{- end }} + + output { +{{- if and .logs .Values.logs.enabled }} + logs = {{ .logs }} +{{- end }} + } +} +{{- end }} \ No newline at end of file diff --git a/grafana/charts/feature-application-observability/templates/_connector_span_metrics.tpl b/grafana/charts/feature-application-observability/templates/_connector_span_metrics.tpl new file mode 100644 index 0000000..5aa1e9f --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_connector_span_metrics.tpl @@ -0,0 +1,51 @@ +{{/* Inputs: Values (values) metricsOutput, name */}} +{{/* https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.connector.spanmetrics/ */}} +{{- define "feature.applicationObservability.connector.spanmetrics.alloy.target" }}otelcol.connector.spanmetrics.{{ .name | default "default" }}.input{{- end }} +{{- define "feature.applicationObservability.connector.spanmetrics.alloy" }} +otelcol.connector.spanmetrics "{{ .name | default "default" }}" { +{{- range $dimension := .Values.connectors.spanMetrics.dimensions }} + dimension { + name = {{ $dimension.name | quote }} +{{- if $dimension.default }} + default = {{ $dimension.default | quote }} +{{- end }} + } +{{- end }} + dimensions_cache_size = {{ .Values.connectors.spanMetrics.dimensionsCacheSize }} + namespace = {{ .Values.connectors.spanMetrics.namespace | quote }} +{{- if .Values.connectors.spanMetrics.events.enabled }} + events { + enabled = true + } +{{- end }} +{{ if .Values.connectors.spanMetrics.exemplars.enabled }} + exemplars { + enabled = true +{{- if .Values.connectors.spanMetrics.exemplars.maxPerDataPoint }} + max_per_data_point = {{ .Values.connectors.spanMetrics.exemplars.maxPerDataPoint }} +{{- end }} + } +{{- end }} +{{- if .Values.connectors.spanMetrics.histogram.enabled }} + histogram { + disable = false + unit = {{ .Values.connectors.spanMetrics.histogram.unit | quote }} +{{- if eq .Values.connectors.spanMetrics.histogram.type "explicit" }} + explicit { + buckets = {{ .Values.connectors.spanMetrics.histogram.explicit.buckets | toJson }} + } +{{- else if eq .Values.connectors.spanMetrics.histogram.type "exponential" }} + exponential { + max_size = {{ .Values.connectors.spanMetrics.histogram.exponential.maxSize }} + } +{{- end }} + } +{{- end }} + + output { +{{- if and .metrics .Values.metrics.enabled }} + metrics = {{ .metrics }} +{{- end }} + } +} +{{- end }} \ No newline at end of file diff --git a/grafana/charts/feature-application-observability/templates/_helpers.tpl b/grafana/charts/feature-application-observability/templates/_helpers.tpl new file mode 100644 index 0000000..edef617 --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_helpers.tpl @@ -0,0 +1,30 @@ +{{/* +Create a default fully qualified 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 "feature.applicationObservability.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" | lower }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride | lower }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" | lower }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" | lower }} +{{- end }} +{{- end }} +{{- end }} + +{{- define "english_list" }} +{{- if eq (len .) 0 }} +{{- else if eq (len .) 1 }} +{{- index . 0 }} +{{- else if eq (len .) 2 }} +{{- index . 0 }} and {{ index . 1 }} +{{- else }} +{{- $last := index . (sub (len .) 1) }} +{{- $rest := slice . 0 (sub (len .) 1) }} +{{- join ", " $rest }}, and {{ $last }} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-application-observability/templates/_module.alloy.tpl b/grafana/charts/feature-application-observability/templates/_module.alloy.tpl new file mode 100644 index 0000000..41d471a --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_module.alloy.tpl @@ -0,0 +1,36 @@ +{{- define "feature.applicationObservability.module" }} +declare "application_observability" { + argument "metrics_destinations" { + comment = "Must be a list of metrics destinations where collected metrics should be forwarded to" + } + + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + argument "traces_destinations" { + comment = "Must be a list of trace destinations where collected trace should be forwarded to" + } +{{- $pipeline := include "feature.applicationObservability.pipeline" . | fromYamlArray }} +{{- range $component := $pipeline }} + {{- $args := (dict "Values" $.Values "name" $component.name) }} + + {{- range $dataType := (list "metrics" "logs" "traces")}} + {{- if kindIs "string" (index $component.targets $dataType) }} + {{- $args = merge $args (dict $dataType (index $component.targets $dataType)) }} + {{- else if kindIs "slice" (index $component.targets $dataType) }} + {{- $targets := list }} + {{- range $target := (index $component.targets $dataType) }} + {{- $targets = append $targets (include (printf "feature.applicationObservability.%s.alloy.target" $target.component) $target) }} + {{- end }} + {{- $args = merge $args (dict $dataType (printf "[%s]" (join ", " $targets))) }} + {{- end }} + {{- end }} + + // {{ $component.description | trim }} + {{- include (printf "feature.applicationObservability.%s.alloy" $component.component) $args | indent 2 }} +{{- end }} +} +{{- end }} + +{{- define "feature.applicationObservability.alloyModules" }}{{- end }} diff --git a/grafana/charts/feature-application-observability/templates/_notes.tpl b/grafana/charts/feature-application-observability/templates/_notes.tpl new file mode 100644 index 0000000..6deeba2 --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_notes.tpl @@ -0,0 +1,52 @@ +{{- define "feature.applicationObservability.notes.deployments" }}{{- end }} + +{{- define "feature.applicationObservability.notes.task" }} +{{- $receivers := list }} +{{- if .Values.receivers.otlp.grpc.enabled }}{{- $receivers = append $receivers "OTLP gRPC" }}{{ end }} +{{- if .Values.receivers.otlp.http.enabled }}{{- $receivers = append $receivers "OTLP HTTP" }}{{ end }} +{{- if .Values.receivers.jaeger.grpc.enabled }}{{- $receivers = append $receivers "Jaeger gRPC" }}{{ end }} +{{- if .Values.receivers.jaeger.thriftBinary.enabled }}{{- $receivers = append $receivers "Jaeger Thrift Binary" }}{{ end }} +{{- if .Values.receivers.jaeger.thriftCompact.enabled }}{{- $receivers = append $receivers "Jaeger Thrift Compact" }}{{ end }} +{{- if .Values.receivers.jaeger.thriftHttp.enabled }}{{- $receivers = append $receivers "Jaeger Thrift HTTP" }}{{ end }} +{{- if .Values.receivers.zipkin.enabled }}{{- $receivers = append $receivers "Zipkin" }}{{ end }} +{{- $receiverWord := len $receivers | plural "receiver" "receivers" }} +Gather application data via {{ include "english_list" $receivers }} {{ $receiverWord }} +{{- end }} + +{{- define "feature.applicationObservability.notes.actions" }} +Configure your applications to send telemetry data to: +{{- if .Values.receivers.otlp.grpc.enabled }} +* http://{{ .Collector.ServiceName }}.{{ .Collector.Namespace }}.svc.cluster.local:{{ .Values.receivers.otlp.grpc.port }} (OTLP gRPC) +{{- end }} +{{- if .Values.receivers.otlp.http.enabled }} +* http://{{ .Collector.ServiceName }}.{{ .Collector.Namespace }}.svc.cluster.local:{{ .Values.receivers.otlp.http.port }} (OTLP HTTP) +{{- end }} +{{- if .Values.receivers.jaeger.grpc.enabled }} +* http://{{ .Collector.ServiceName }}.{{ .Collector.Namespace }}.svc.cluster.local:{{ .Values.receivers.jaeger.grpc.port }} (Jaeger gRPC) +{{- end }} +{{- if .Values.receivers.jaeger.thriftBinary.enabled }} +* http://{{ .Collector.ServiceName }}.{{ .Collector.Namespace }}.svc.cluster.local:{{ .Values.receivers.jaeger.thriftBinary.port }} (Jaeger Thrift Binary) +{{- end }} +{{- if .Values.receivers.jaeger.thriftCompact.enabled }} +* http://{{ .Collector.ServiceName }}.{{ .Collector.Namespace }}.svc.cluster.local:{{ .Values.receivers.jaeger.thriftCompact.port }} (Jaeger Thrift Compact) +{{- end }} +{{- if .Values.receivers.jaeger.thriftHttp.enabled }} +* http://{{ .Collector.ServiceName }}.{{ .Collector.Namespace }}.svc.cluster.local:{{ .Values.receivers.jaeger.thriftHttp.port }} (Jaeger Thrift HTTP) +{{- end }} +{{- if .Values.receivers.zipkin.enabled }} +* http://{{ .Collector.ServiceName }}.{{ .Collector.Namespace }}.svc.cluster.local:{{ .Values.receivers.zipkin.port }} (Zipkin) +{{- end }} +{{- end }} + +{{- define "feature.applicationObservability.summary" -}} +{{- $receivers := list }} +{{- if .Values.receivers.otlp.grpc.enabled }}{{- $receivers = append $receivers "otlpgrpc" }}{{ end }} +{{- if .Values.receivers.otlp.http.enabled }}{{- $receivers = append $receivers "otlphttp" }}{{ end }} +{{- if .Values.receivers.jaeger.grpc.enabled }}{{- $receivers = append $receivers "jaegergrpc" }}{{ end }} +{{- if .Values.receivers.jaeger.thriftBinary.enabled }}{{- $receivers = append $receivers "jaegerthriftbinary" }}{{ end }} +{{- if .Values.receivers.jaeger.thriftCompact.enabled }}{{- $receivers = append $receivers "jaegerthriftcompact" }}{{ end }} +{{- if .Values.receivers.jaeger.thriftHttp.enabled }}{{- $receivers = append $receivers "jaegerthrifthttp" }}{{ end }} +{{- if .Values.receivers.zipkin.enabled }}{{- $receivers = append $receivers "zipkin" }}{{ end }} +version: {{ .Chart.Version }} +protocols: {{ $receivers | join "," }} +{{- end }} diff --git a/grafana/charts/feature-application-observability/templates/_pipeline.tpl b/grafana/charts/feature-application-observability/templates/_pipeline.tpl new file mode 100644 index 0000000..7b142f7 --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_pipeline.tpl @@ -0,0 +1,161 @@ +{{- define "feature.applicationObservability.pipeline" }} +# Format: +# - name: Alloy component name +# description: Human friendly description of the component +# component: Component slug (used for including "feature.applicationObservability.%s.alloy") +# targets: +# : +# - name: Name of the target +# component: Component slug (used for including "feature.applicationObservability.%s.alloy.target") +# : Raw target string (useful for terminating with argument._destinations.value) +# : No target defined for this type +{{- if or .Values.receivers.otlp.grpc.enabled .Values.receivers.otlp.http.enabled }} +- name: default + description: OTLP Receiver + component: receiver.otlp + targets: +{{- if .Values.processors.memoryLimiter.enabled }} + metrics: [{name: default, component: processor.memory_limiter}] + logs: [{name: default, component: processor.memory_limiter}] + traces: [{name: default, component: processor.memory_limiter}] +{{- else }} + metrics: [{name: default, component: processor.resourcedetection}] + logs: [{name: default, component: processor.resourcedetection}] + traces: [{name: default, component: processor.resourcedetection}] +{{- end }} +{{- end }} +{{- if or .Values.receivers.jaeger.grpc.enabled .Values.receivers.jaeger.thriftBinary.enabled .Values.receivers.jaeger.thriftCompact.enabled .Values.receivers.jaeger.thriftHttp.enabled }} +- name: default + description: Jaeger Receiver + component: receiver.jaeger + targets: +{{- if .Values.processors.memoryLimiter.enabled }} + traces: [{name: default, component: processor.memory_limiter}] +{{- else }} + traces: [{name: default, component: processor.resourcedetection}] +{{- end }} +{{- end }} +{{- if .Values.receivers.zipkin.enabled }} +- name: default + description: Zipkin Receiver + component: receiver.zipkin + targets: +{{- if .Values.processors.memoryLimiter.enabled }} + traces: [{name: default, component: processor.memory_limiter}] +{{- else }} + traces: [{name: default, component: processor.resourcedetection}] +{{- end }} +{{- end }} + +{{- if .Values.processors.memoryLimiter.enabled }} +- name: default + description: Memory Limiter + component: processor.memory_limiter + targets: + metrics: [{name: default, component: processor.resourcedetection}] + logs: [{name: default, component: processor.resourcedetection}] + traces: [{name: default, component: processor.resourcedetection}] +{{- end }} + + +- name: default + description: Resource Detection Processor + component: processor.resourcedetection + targets: + metrics: [{name: default, component: processor.k8sattributes}] + logs: [{name: default, component: processor.k8sattributes}] + traces: [{name: default, component: processor.k8sattributes}] + +- name: default + description: K8s Attributes Processor + component: processor.k8sattributes + targets: + metrics: [{name: default, component: processor.transform}] + logs: [{name: default, component: processor.transform}] +{{- if (index .Values.processors "grafanaCloudMetrics").enabled | default .Values.connectors.grafanaCloudMetrics.enabled }} + traces: [{name: default, component: processor.transform}, {name: default, component: connector.host_info}] + +- name: default + description: Host Info Connector + component: connector.host_info + targets: + metrics: [{name: default, component: processor.batch}] +{{- else }} + traces: [{name: default, component: processor.transform}] +{{- end }} + +{{- $filterEnabled := eq (include "feature.applicationObservability.processor.filter.enabled" .) "true" }} +- name: default + description: Transform Processor + component: processor.transform + targets: + traces: [{name: default, component: processor.batch}] + traces: +{{- if .Values.connectors.spanLogs.enabled}} + - {name: default, component: connector.spanlogs} +{{- end }} +{{- if .Values.connectors.spanMetrics.enabled}} + - {name: default, component: connector.spanmetrics} +{{- end }} +{{- if $filterEnabled }} + - {name: default, component: processor.filter} + metrics: [{name: default, component: processor.filter}] + logs: [{name: default, component: processor.filter}] +{{- else }} + - {name: default, component: processor.batch} + metrics: [{name: default, component: processor.batch}] + logs: [{name: default, component: processor.batch}] +{{- end }} + +{{- if .Values.connectors.spanLogs.enabled}} +- name: default + description: Span Logs Connector + component: connector.spanlogs + targets: +{{- if $filterEnabled }} + logs: [{name: default, component: processor.filter}] +{{- else }} + logs: [{name: default, component: processor.batch}] +{{- end }} +{{- end }} +{{- if .Values.connectors.spanMetrics.enabled}} +- name: default + description: Span Metrics Connector + component: connector.spanmetrics + targets: +{{- if $filterEnabled }} + metrics: [{name: default, component: processor.filter}] +{{- else }} + metrics: [{name: default, component: processor.batch}] +{{- end }} +{{- end }} + +{{- if $filterEnabled }} +- name: default + description: Filter Processor + component: processor.filter + targets: + metrics: [{name: default, component: processor.batch}] + logs: [{name: default, component: processor.batch}] + traces: [{name: default, component: processor.batch}] +{{- end }} + +- name: default + description: Batch Processor + component: processor.batch + targets: +{{- if .Values.processors.interval.enabled }} + metrics: [{name: default, component: processor.interval}] + logs: [{name: default, component: processor.interval}] + traces: [{name: default, component: processor.interval}] + +- name: default + description: Interval Processor + component: processor.interval + targets: +{{- end }} + metrics: argument.metrics_destinations.value + logs: argument.logs_destinations.value + traces: argument.traces_destinations.value + +{{- end }} diff --git a/grafana/charts/feature-application-observability/templates/_processor_batch.tpl b/grafana/charts/feature-application-observability/templates/_processor_batch.tpl new file mode 100644 index 0000000..146596e --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_processor_batch.tpl @@ -0,0 +1,21 @@ +{{/* Inputs: Values (values) metricsOutput, logsOutput, tracesOutput, name */}} +{{- define "feature.applicationObservability.processor.batch.alloy.target" }}otelcol.processor.batch.{{ .name | default "default" }}.input{{ end }} +{{- define "feature.applicationObservability.processor.batch.alloy" }} +otelcol.processor.batch {{ .name | default "default" | quote }} { + send_batch_size = {{ .Values.processors.batch.size }} + send_batch_max_size = {{ .Values.processors.batch.maxSize }} + timeout = {{ .Values.processors.batch.timeout | quote}} + + output { +{{- if and .metrics .Values.metrics.enabled }} + metrics = {{ .metrics }} +{{- end }} +{{- if and .logs .Values.logs.enabled }} + logs = {{ .logs }} +{{- end }} +{{- if and .traces .Values.traces.enabled }} + traces = {{ .traces }} +{{- end }} + } +} +{{- end }} \ No newline at end of file diff --git a/grafana/charts/feature-application-observability/templates/_processor_filter.tpl b/grafana/charts/feature-application-observability/templates/_processor_filter.tpl new file mode 100644 index 0000000..b4cae96 --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_processor_filter.tpl @@ -0,0 +1,74 @@ +{{/* Inputs: Values (values) metricsOutput, logsOutput, tracesOutput, name */}} +{{/* https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.filter/ */}} +{{- define "feature.applicationObservability.processor.filter.enabled" }} +{{- if and .Values.metrics.enabled (or .Values.metrics.filters.metric .Values.metrics.filters.datapoint) -}} +true +{{- else if and .Values.logs.enabled .Values.logs.filters.log_record -}} +true +{{- else if and .Values.traces.enabled (or .Values.traces.filters.span .Values.traces.filters.spanevent) -}} +true +{{- else -}} +false +{{- end }} +{{- end }} +{{- define "feature.applicationObservability.processor.filter.alloy.target" }}otelcol.processor.filter.{{ .name | default "default" }}.input{{ end }} +{{- define "feature.applicationObservability.processor.filter.alloy" }} +otelcol.processor.filter "{{ .name | default "default" }}" { +{{- if and .Values.metrics.enabled (or .Values.metrics.filters.metric .Values.metrics.filters.datapoint) }} + metrics { +{{- if .Values.metrics.filters.metric }} + metric = [ +{{- range $filter := .Values.metrics.filters.metric }} +{{ $filter | quote | indent 6 }}, +{{- end }} + ] +{{- end }} +{{- if .Values.metrics.filters.datapoint }} + datapoint = [ +{{- range $filter := .Values.metrics.filters.datapoint }} +{{ $filter | quote | indent 6 }}, +{{- end }} + ] +{{- end }} + } +{{- end }} +{{- if and .Values.logs.enabled .Values.logs.filters.log_record }} + logs { + log_record = [ +{{- range $filter := .Values.logs.filters.log_record }} +{{ $filter | quote | indent 6 }}, +{{- end }} + ] + } +{{- end }} +{{- if and .Values.traces.enabled (or .Values.traces.filters.span .Values.traces.filters.spanevent) }} + traces { +{{- if .Values.traces.filters.span }} + span = [ +{{- range $filter := .Values.traces.filters.span }} +{{ $filter | quote | indent 6 }}, +{{- end }} + ] +{{- end }} +{{- if .Values.traces.filters.spanevent }} + spanevent = [ +{{- range $filter := .Values.traces.filters.spanevent }} +{{ $filter | quote | indent 6 }}, +{{- end }} + ] +{{- end }} + } +{{- end }} + output { +{{- if and .metrics .Values.metrics.enabled }} + metrics = {{ .metrics }} +{{- end }} +{{- if and .logs .Values.logs.enabled }} + logs = {{ .logs }} +{{- end }} +{{- if and .traces .Values.traces.enabled }} + traces = {{ .traces }} +{{- end }} + } +} +{{- end }} \ No newline at end of file diff --git a/grafana/charts/feature-application-observability/templates/_processor_interval.tpl b/grafana/charts/feature-application-observability/templates/_processor_interval.tpl new file mode 100644 index 0000000..04fdecf --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_processor_interval.tpl @@ -0,0 +1,23 @@ +{{/* Inputs: Values (values) metricsOutput, logsOutput, tracesOutput, name */}} +{{- define "feature.applicationObservability.processor.interval.alloy.target" }}otelcol.processor.interval.{{ .name | default "default" }}.input{{ end }} +{{- define "feature.applicationObservability.processor.interval.alloy" }} +otelcol.processor.interval {{ .name | default "default" | quote }} { + interval = {{ .Values.processors.interval.interval | quote }} + passthrough { + gauge = {{ .Values.processors.interval.passthrough.gauge }} + summary = {{ .Values.processors.interval.passthrough.summary }} + } + + output { +{{- if and .metrics .Values.metrics.enabled }} + metrics = {{ .metrics }} +{{- end }} +{{- if and .logs .Values.logs.enabled }} + logs = {{ .logs }} +{{- end }} +{{- if and .traces .Values.traces.enabled }} + traces = {{ .traces }} +{{- end }} + } +} +{{- end }} \ No newline at end of file diff --git a/grafana/charts/feature-application-observability/templates/_processor_k8sattributes.tpl b/grafana/charts/feature-application-observability/templates/_processor_k8sattributes.tpl new file mode 100644 index 0000000..6d50002 --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_processor_k8sattributes.tpl @@ -0,0 +1,55 @@ +{{/* Inputs: Values (values) metricsOutput, logsOutput, tracesOutput, name */}} +{{/* https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.k8sattributes/ */}} +{{- define "feature.applicationObservability.processor.k8sattributes.alloy.target" }}otelcol.processor.k8sattributes.{{ .name | default "default" }}.input{{ end }} +{{- define "feature.applicationObservability.processor.k8sattributes.alloy" }} +otelcol.processor.k8sattributes "{{ .name | default "default" }}" { + extract { +{{- if .Values.processors.k8sattributes.metadata }} + metadata = {{ .Values.processors.k8sattributes.metadata | toJson }} +{{- end }} +{{- range .Values.processors.k8sattributes.labels }} + label { + {{- range $k, $v := . }} + {{ $k }} = {{ $v | quote }} + {{- end }} + } +{{- end }} +{{- range .Values.processors.k8sattributes.annotations }} + annotation { + {{- range $k, $v := . }} + {{ $k }} = {{ $v | quote }} + {{- end }} + } +{{- end }} + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.ip" + } + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.uid" + } + } + pod_association { + source { + from = "connection" + } + } + + output { +{{- if and .metrics .Values.metrics.enabled }} + metrics = {{ .metrics }} +{{- end }} +{{- if and .logs .Values.logs.enabled }} + logs = {{ .logs }} +{{- end }} +{{- if and .traces .Values.traces.enabled }} + traces = {{ .traces }} +{{- end }} + } +} +{{- end }} \ No newline at end of file diff --git a/grafana/charts/feature-application-observability/templates/_processor_memory_limiter.tpl b/grafana/charts/feature-application-observability/templates/_processor_memory_limiter.tpl new file mode 100644 index 0000000..86754e2 --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_processor_memory_limiter.tpl @@ -0,0 +1,20 @@ +{{/* Inputs: Values (values) metricsOutput, logsOutput, tracesOutput, name */}} +{{- define "feature.applicationObservability.processor.memory_limiter.alloy.target" }}otelcol.processor.memory_limiter.{{ .name | default "default" }}.input{{ end }} +{{- define "feature.applicationObservability.processor.memory_limiter.alloy" }} +otelcol.processor.memory_limiter "{{ .name | default "default" }}" { + check_interval = {{ .Values.processors.memoryLimiter.checkInterval | quote }} + limit = {{ .Values.processors.memoryLimiter.limit | quote }} + + output { +{{- if and .metrics .Values.metrics.enabled }} + metrics = {{ .metrics }} +{{- end }} +{{- if and .logs .Values.logs.enabled }} + logs = {{ .logs }} +{{- end }} +{{- if and .traces .Values.traces.enabled }} + traces = {{ .traces }} +{{- end }} + } +} +{{- end }} \ No newline at end of file diff --git a/grafana/charts/feature-application-observability/templates/_processor_resourcedetection.tpl b/grafana/charts/feature-application-observability/templates/_processor_resourcedetection.tpl new file mode 100644 index 0000000..423b58b --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_processor_resourcedetection.tpl @@ -0,0 +1,89 @@ +{{/* Inputs: Values (values) metricsOutput, logsOutput, tracesOutput, name */}} +{{/* https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.resourcedetection/ */}} +{{- define "feature.applicationObservability.processor.resourcedetection.alloy.target" }}otelcol.processor.resourcedetection.{{ .name | default "default" }}.input{{ end }} +{{- define "feature.applicationObservability.processor.resourcedetection.alloy" }} +{{- $detectors := include "feature.applicationObservability.processor.resourcedetection.detectors" . | fromYamlArray }} +otelcol.processor.resourcedetection "{{ .name | default "default" }}" { + detectors = {{ $detectors | sortAlpha | toJson }} + override = {{ .Values.processors.resourceDetection.override }} + +{{- range $detector := $detectors }} + {{- /* Skip env, it has no settings */}} + {{- if ne $detector "env" }} + {{ $detectorValues := index $.Values.processors.resourceDetection $detector }} + + {{- /* Fix the case style for kubernetesNode --> kubernetes_node */}} + {{- if eq $detector "kubernetesNode" }} + kubernetes_node { + {{- else }} + {{ $detector }} { + {{- end }} + + {{- /* Handle detectors with special arguments */}} + {{- if eq $detector "ec2" }} + {{- if $detectorValues.tags }} + tags = {{ $detectorValues.tags | toJson }} + {{- end }} + {{- end }} + {{- if eq $detector "consul" }} + {{ if $detectorValues.address }}address = {{ $detectorValues.address | quote }}{{ end }} + {{ if $detectorValues.datacenter }}datacenter = {{ $detectorValues.datacenter | quote }}{{ end }} + {{ if $detectorValues.token }}token = {{ $detectorValues.token | quote }}{{ end }} + {{ if $detectorValues.namespace }}namespace = {{ $detectorValues.namespace | quote }}{{ end }} + {{ if $detectorValues.meta }}meta = {{ $detectorValues.meta | toJson }}{{ end }} + {{- end }} + {{- if eq $detector "system" }} + {{- if $detectorValues.hostnameSources }} + hostname_sources = {{ $detectorValues.hostnameSources | toJson }} + {{- end }} + {{- end }} + {{- if eq $detector "openshift" }} + {{ if $detectorValues.address }}address = {{ $detectorValues.address | quote }}{{ end }} + {{ if $detectorValues.token }}token = {{ $detectorValues.token | quote }}{{ end }} + {{- end }} + {{- if eq $detector "kubernetesNode" }} + {{ if $detectorValues.authType }}auth_type = {{ $detectorValues.authType | quote }}{{ end }} + {{ if $detectorValues.nodeFromEnvVar }}node_from_env_var = {{ $detectorValues.nodeFromEnvVar | quote }}{{ end }} + {{- end }} + + {{- if $detectorValues.resourceAttributes }} + resource_attributes { + {{- range $key, $value := $detectorValues.resourceAttributes }} + {{ if $value.enabled }}{{ $key }} { enabled = true }{{ end }} + {{- end }} + } + {{- end }} + } + {{- end }} +{{- end }} + + output { +{{- if and .metrics .Values.metrics.enabled }} + metrics = {{ .metrics }} +{{- end }} +{{- if and .logs .Values.logs.enabled }} + logs = {{ .logs }} +{{- end }} +{{- if and .traces .Values.traces.enabled }} + traces = {{ .traces }} +{{- end }} + } +} +{{- end }} + +{{- define "feature.applicationObservability.processor.resourcedetection.detectors" }} +{{- $enabledDetectors := list }} +{{- range $detector, $options := .Values.processors.resourceDetection }} + {{- if ne $detector "override" }} + {{- if $options.enabled }} + {{- $enabledDetectors = append $enabledDetectors $detector }} + {{- end }} + {{- end }} +{{- end }} +{{ $enabledDetectors | toJson }} +{{- end }} + +{{- define "feature.applicationObservability.processor.resourcedetection.enabled" }} +{{- $detectors := include "feature.applicationObservability.processor.resourcedetection.detectors" . | fromYamlArray }} +{{- gt (len $detectors) 0 }} +{{- end }} diff --git a/grafana/charts/feature-application-observability/templates/_processor_transform.tpl b/grafana/charts/feature-application-observability/templates/_processor_transform.tpl new file mode 100644 index 0000000..3d77434 --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_processor_transform.tpl @@ -0,0 +1,110 @@ +{{/* Inputs: Values (values) metricsOutput, logsOutput, tracesOutput, name */}} +{{/* https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.transform/ */}} +{{- define "feature.applicationObservability.processor.transform.alloy.target" }}otelcol.processor.transform.{{ .name | default "default" }}.input{{ end }} +{{- define "feature.applicationObservability.processor.transform.alloy" }} +otelcol.processor.transform "{{ .name | default "default" }}" { + error_mode = "ignore" + +{{- if .Values.metrics.enabled }} +{{- if .Values.metrics.transforms.resource }} + metric_statements { + context = "resource" + statements = [ +{{- range $transform := .Values.metrics.transforms.resource }} +{{ $transform | quote | indent 6 }}, +{{- end }} + ] + } +{{- end }} +{{- if .Values.metrics.transforms.metric }} + metric_statements { + context = "metric" + statements = [ +{{- range $transform := .Values.metrics.transforms.metric }} +{{ $transform | quote | indent 6 }}, +{{- end }} + ] + } +{{- end }} +{{- if .Values.metrics.transforms.datapoint }} + metric_statements { + context = "datapoint" + statements = [ +{{- range $transform := .Values.metrics.transforms.datapoint }} +{{ $transform | quote | indent 6 }}, +{{- end }} + ] + } +{{- end }} +{{- end }} +{{- if .Values.logs.enabled }} + log_statements { + context = "resource" + statements = [ +{{- if .Values.logs.transforms.resource }} +{{- range $transform := .Values.logs.transforms.resource }} +{{ $transform | quote | indent 6 }}, +{{- end }} +{{- end }} + "set(attributes[\"pod\"], attributes[\"k8s.pod.name\"])", + "set(attributes[\"namespace\"], attributes[\"k8s.namespace.name\"])", + "set(attributes[\"loki.resource.labels\"], \"{{ .Values.logs.transforms.labels | join ", " }}\")", + ] + } +{{- if .Values.logs.transforms.log }} + log_statements { + context = "log" + statements = [ +{{- range $transform := .Values.logs.transforms.log }} +{{ $transform | quote | indent 6 }}, +{{- end }} + ] + } +{{- end }} +{{- end }} +{{- if .Values.traces.enabled }} +{{- if .Values.traces.transforms.resource }} + trace_statements { + context = "resource" + statements = [ +{{- range $transform := .Values.traces.transforms.resource }} +{{ $transform | quote | indent 6 }}, +{{- end }} + ] + } +{{- end }} +{{- if .Values.traces.transforms.span }} + trace_statements { + context = "span" + statements = [ +{{- range $transform := .Values.traces.transforms.span }} +{{ $transform | quote | indent 6 }}, +{{- end }} + ] + } +{{- end }} +{{- if .Values.traces.transforms.spanevent }} + trace_statements { + context = "spanevent" + statements = [ +{{- range $transform := .Values.traces.transforms.spanevent }} +{{ $transform | quote | indent 6 }}, +{{- end }} + ] + } +{{- end }} +{{- end }} + + output { +{{- if and .metrics .Values.metrics.enabled }} + metrics = {{ .metrics }} +{{- end }} +{{- if and .logs .Values.logs.enabled }} + logs = {{ .logs }} +{{- end }} +{{- if and .traces .Values.traces.enabled }} + traces = {{ .traces }} +{{- end }} + } +} +{{- end }} \ No newline at end of file diff --git a/grafana/charts/feature-application-observability/templates/_receiver_jaeger.tpl b/grafana/charts/feature-application-observability/templates/_receiver_jaeger.tpl new file mode 100644 index 0000000..bb400e1 --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_receiver_jaeger.tpl @@ -0,0 +1,36 @@ +{{/* Inputs: Values (values) tracesOutput */}} +{{- define "feature.applicationObservability.receiver.jaeger.alloy" }} +otelcol.receiver.jaeger "receiver" { + protocols { +{{- if .Values.receivers.jaeger.grpc.enabled }} + grpc { + endpoint = "0.0.0.0:{{ .Values.receivers.jaeger.grpc.port | int }}" + } +{{- end }} +{{- if .Values.receivers.jaeger.thriftBinary.enabled }} + thrift_binary { + endpoint = "0.0.0.0:{{ .Values.receivers.jaeger.thriftBinary.port | int }}" + } +{{- end }} +{{- if .Values.receivers.jaeger.thriftCompact.enabled }} + thrift_compact { + endpoint = "0.0.0.0:{{ .Values.receivers.jaeger.thriftCompact.port | int }}" + } +{{- end }} +{{- if .Values.receivers.jaeger.thriftHttp.enabled }} + thrift_http { + endpoint = "0.0.0.0:{{ .Values.receivers.jaeger.thriftHttp.port | int }}" + } +{{- end }} + } + + debug_metrics { + disable_high_cardinality_metrics = {{ not .Values.receivers.jaeger.includeDebugMetrics }} + } + output { +{{- if and .traces .Values.traces.enabled }} + traces = {{ .traces }} +{{- end }} + } +} +{{- end }} diff --git a/grafana/charts/feature-application-observability/templates/_receiver_otlp.tpl b/grafana/charts/feature-application-observability/templates/_receiver_otlp.tpl new file mode 100644 index 0000000..32e4fba --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_receiver_otlp.tpl @@ -0,0 +1,36 @@ +{{/* Inputs: Values (values) metricsOutput, logsOutput, tracesOutput */}} +{{- define "feature.applicationObservability.receiver.otlp.alloy" }} +otelcol.receiver.otlp "receiver" { +{{- if .Values.receivers.otlp.grpc.enabled }} + grpc { + endpoint = "0.0.0.0:{{ .Values.receivers.otlp.grpc.port | int }}" + max_recv_msg_size = {{ .Values.receivers.otlp.grpc.maxReceivedMessageSize | quote }} +{{- if ne (int .Values.receivers.otlp.grpc.maxConcurrentStreams) 0 }} + max_concurrent_streams = {{ .Values.receivers.otlp.grpc.maxConcurrentStreams }} +{{- end }} + read_buffer_size = {{ .Values.receivers.otlp.grpc.readBufferSize | quote }} + write_buffer_size = {{ .Values.receivers.otlp.grpc.writeBufferSize | quote }} + } +{{- end }} +{{- if .Values.receivers.otlp.http.enabled }} + http { + endpoint = "0.0.0.0:{{ .Values.receivers.otlp.http.port | int }}" + max_request_body_size = {{ .Values.receivers.otlp.http.maxRequestBodySize | quote }} + } +{{- end }} + debug_metrics { + disable_high_cardinality_metrics = {{ not .Values.receivers.otlp.includeDebugMetrics }} + } + output { +{{- if and .metrics .Values.metrics.enabled }} + metrics = {{ .metrics }} +{{- end }} +{{- if and .logs .Values.logs.enabled }} + logs = {{ .logs }} +{{- end }} +{{- if and .traces .Values.traces.enabled }} + traces = {{ .traces }} +{{- end }} + } +} +{{- end }} diff --git a/grafana/charts/feature-application-observability/templates/_receiver_zipkin.tpl b/grafana/charts/feature-application-observability/templates/_receiver_zipkin.tpl new file mode 100644 index 0000000..73efff7 --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_receiver_zipkin.tpl @@ -0,0 +1,14 @@ +{{/* Inputs: Values (values) tracesOutput */}} +{{- define "feature.applicationObservability.receiver.zipkin.alloy" }} +otelcol.receiver.zipkin "receiver" { + endpoint = "0.0.0.0:{{ .Values.receivers.zipkin.port | int }}" + debug_metrics { + disable_high_cardinality_metrics = {{ not .Values.receivers.zipkin.includeDebugMetrics }} + } + output { +{{- if and .traces .Values.traces.enabled }} + traces = {{ .traces }} +{{- end }} + } +} +{{- end }} diff --git a/grafana/charts/feature-application-observability/templates/_validation.tpl b/grafana/charts/feature-application-observability/templates/_validation.tpl new file mode 100644 index 0000000..0e7e539 --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/_validation.tpl @@ -0,0 +1,16 @@ +{{- define "feature.applicationObservability.validate" }} +{{- $aRecevierIsEnabled := or .Values.receivers.otlp.grpc.enabled .Values.receivers.otlp.http.enabled }} +{{- $aRecevierIsEnabled = or $aRecevierIsEnabled .Values.receivers.zipkin.enabled }} +{{- $aRecevierIsEnabled = or $aRecevierIsEnabled .Values.receivers.jaeger.grpc.enabled .Values.receivers.jaeger.thriftBinary.enabled .Values.receivers.jaeger.thriftCompact.enabled .Values.receivers.jaeger.thriftHttp.enabled }} +{{- if not $aRecevierIsEnabled }} + {{- $msg := list "" "At least one receiver must be enabled to use Application Observability." }} + {{- $msg = append $msg "Please enable one. For example:" }} + {{- $msg = append $msg "applicationObservability:" }} + {{- $msg = append $msg " receivers:" }} + {{- $msg = append $msg " otlp:" }} + {{- $msg = append $msg " grpc:" }} + {{- $msg = append $msg " enabled: true" }} + {{- $msg = append $msg "See https://github.com/grafana/k8s-monitoring-helm/tree/main/charts/k8s-monitoring/charts/feature-application-observability for more details." }} + {{- fail (join "\n" $msg) }} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-application-observability/templates/configmap.yaml b/grafana/charts/feature-application-observability/templates/configmap.yaml new file mode 100644 index 0000000..190a187 --- /dev/null +++ b/grafana/charts/feature-application-observability/templates/configmap.yaml @@ -0,0 +1,14 @@ +{{- if .Values.deployAsConfigMap }} +{{- include "feature.applicationObservability.validate" . }} +{{- $alloyConfig := include "feature.applicationObservability.module" . }} +{{- $alloyConfig = regexReplaceAll `[ \t]+(\r?\n)` $alloyConfig "\n" }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "feature.applicationObservability.fullname" . }} + namespace: {{ .Release.Namespace }} +data: + module.alloy: |- + {{- $alloyConfig | trim | nindent 4 }} +{{- end }} diff --git a/grafana/charts/feature-application-observability/tests/__snapshot__/.gitkeep b/grafana/charts/feature-application-observability/tests/__snapshot__/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/grafana/charts/feature-application-observability/tests/__snapshot__/default_test.yaml.snap b/grafana/charts/feature-application-observability/tests/__snapshot__/default_test.yaml.snap new file mode 100644 index 0000000..16e3be1 --- /dev/null +++ b/grafana/charts/feature-application-observability/tests/__snapshot__/default_test.yaml.snap @@ -0,0 +1,161 @@ +creates the default pipeline: + 1: | + |- + declare "application_observability" { + argument "metrics_destinations" { + comment = "Must be a list of metrics destinations where collected metrics should be forwarded to" + } + + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + argument "traces_destinations" { + comment = "Must be a list of trace destinations where collected trace should be forwarded to" + } + + // OTLP Receiver + otelcol.receiver.otlp "receiver" { + grpc { + endpoint = "0.0.0.0:4317" + max_recv_msg_size = "4MiB" + read_buffer_size = "512KiB" + write_buffer_size = "32KiB" + } + http { + endpoint = "0.0.0.0:4318" + max_request_body_size = "20MiB" + } + debug_metrics { + disable_high_cardinality_metrics = true + } + output { + metrics = [otelcol.processor.resourcedetection.default.input] + logs = [otelcol.processor.resourcedetection.default.input] + traces = [otelcol.processor.resourcedetection.default.input] + } + } + + // Jaeger Receiver + otelcol.receiver.jaeger "receiver" { + protocols { + grpc { + endpoint = "0.0.0.0:14250" + } + thrift_binary { + endpoint = "0.0.0.0:6832" + } + thrift_compact { + endpoint = "0.0.0.0:6831" + } + thrift_http { + endpoint = "0.0.0.0:14268" + } + } + + debug_metrics { + disable_high_cardinality_metrics = true + } + output { + traces = [otelcol.processor.resourcedetection.default.input] + } + } + + // Zipkin Receiver + otelcol.receiver.zipkin "receiver" { + endpoint = "0.0.0.0:9411" + debug_metrics { + disable_high_cardinality_metrics = true + } + output { + traces = [otelcol.processor.resourcedetection.default.input] + } + } + + // Resource Detection Processor + otelcol.processor.resourcedetection "default" { + detectors = ["env","system"] + override = true + + system { + hostname_sources = ["os"] + } + + output { + metrics = [otelcol.processor.k8sattributes.default.input] + logs = [otelcol.processor.k8sattributes.default.input] + traces = [otelcol.processor.k8sattributes.default.input] + } + } + + // K8s Attributes Processor + otelcol.processor.k8sattributes "default" { + extract { + metadata = ["k8s.namespace.name","k8s.pod.name","k8s.deployment.name","k8s.statefulset.name","k8s.daemonset.name","k8s.cronjob.name","k8s.job.name","k8s.node.name","k8s.pod.uid","k8s.pod.start_time"] + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.ip" + } + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.uid" + } + } + pod_association { + source { + from = "connection" + } + } + + output { + metrics = [otelcol.processor.transform.default.input] + logs = [otelcol.processor.transform.default.input] + traces = [otelcol.processor.transform.default.input, otelcol.connector.host_info.default.input] + } + } + + // Host Info Connector + otelcol.connector.host_info "default" { + host_identifiers = [ "k8s.node.name" ] + + output { + metrics = [otelcol.processor.batch.default.input] + } + } + + // Transform Processor + otelcol.processor.transform "default" { + error_mode = "ignore" + log_statements { + context = "resource" + statements = [ + "set(attributes[\"pod\"], attributes[\"k8s.pod.name\"])", + "set(attributes[\"namespace\"], attributes[\"k8s.namespace.name\"])", + "set(attributes[\"loki.resource.labels\"], \"cluster, namespace, job, pod\")", + ] + } + + output { + metrics = [otelcol.processor.batch.default.input] + logs = [otelcol.processor.batch.default.input] + traces = [otelcol.processor.batch.default.input] + } + } + + // Batch Processor + otelcol.processor.batch "default" { + send_batch_size = 8192 + send_batch_max_size = 0 + timeout = "2s" + + output { + metrics = argument.metrics_destinations.value + logs = argument.logs_destinations.value + traces = argument.traces_destinations.value + } + } + } diff --git a/grafana/charts/feature-application-observability/tests/__snapshot__/interval_test.yaml.snap b/grafana/charts/feature-application-observability/tests/__snapshot__/interval_test.yaml.snap new file mode 100644 index 0000000..ce465dc --- /dev/null +++ b/grafana/charts/feature-application-observability/tests/__snapshot__/interval_test.yaml.snap @@ -0,0 +1,176 @@ +creates the pipeline with the interval processor: + 1: | + |- + declare "application_observability" { + argument "metrics_destinations" { + comment = "Must be a list of metrics destinations where collected metrics should be forwarded to" + } + + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + argument "traces_destinations" { + comment = "Must be a list of trace destinations where collected trace should be forwarded to" + } + + // OTLP Receiver + otelcol.receiver.otlp "receiver" { + grpc { + endpoint = "0.0.0.0:4317" + max_recv_msg_size = "4MiB" + read_buffer_size = "512KiB" + write_buffer_size = "32KiB" + } + http { + endpoint = "0.0.0.0:4318" + max_request_body_size = "20MiB" + } + debug_metrics { + disable_high_cardinality_metrics = true + } + output { + metrics = [otelcol.processor.resourcedetection.default.input] + logs = [otelcol.processor.resourcedetection.default.input] + traces = [otelcol.processor.resourcedetection.default.input] + } + } + + // Jaeger Receiver + otelcol.receiver.jaeger "receiver" { + protocols { + grpc { + endpoint = "0.0.0.0:14250" + } + thrift_binary { + endpoint = "0.0.0.0:6832" + } + thrift_compact { + endpoint = "0.0.0.0:6831" + } + thrift_http { + endpoint = "0.0.0.0:14268" + } + } + + debug_metrics { + disable_high_cardinality_metrics = true + } + output { + traces = [otelcol.processor.resourcedetection.default.input] + } + } + + // Zipkin Receiver + otelcol.receiver.zipkin "receiver" { + endpoint = "0.0.0.0:9411" + debug_metrics { + disable_high_cardinality_metrics = true + } + output { + traces = [otelcol.processor.resourcedetection.default.input] + } + } + + // Resource Detection Processor + otelcol.processor.resourcedetection "default" { + detectors = ["env","system"] + override = true + + system { + hostname_sources = ["os"] + } + + output { + metrics = [otelcol.processor.k8sattributes.default.input] + logs = [otelcol.processor.k8sattributes.default.input] + traces = [otelcol.processor.k8sattributes.default.input] + } + } + + // K8s Attributes Processor + otelcol.processor.k8sattributes "default" { + extract { + metadata = ["k8s.namespace.name","k8s.pod.name","k8s.deployment.name","k8s.statefulset.name","k8s.daemonset.name","k8s.cronjob.name","k8s.job.name","k8s.node.name","k8s.pod.uid","k8s.pod.start_time"] + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.ip" + } + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.uid" + } + } + pod_association { + source { + from = "connection" + } + } + + output { + metrics = [otelcol.processor.transform.default.input] + logs = [otelcol.processor.transform.default.input] + traces = [otelcol.processor.transform.default.input, otelcol.connector.host_info.default.input] + } + } + + // Host Info Connector + otelcol.connector.host_info "default" { + host_identifiers = [ "k8s.node.name" ] + + output { + metrics = [otelcol.processor.batch.default.input] + } + } + + // Transform Processor + otelcol.processor.transform "default" { + error_mode = "ignore" + log_statements { + context = "resource" + statements = [ + "set(attributes[\"pod\"], attributes[\"k8s.pod.name\"])", + "set(attributes[\"namespace\"], attributes[\"k8s.namespace.name\"])", + "set(attributes[\"loki.resource.labels\"], \"cluster, namespace, job, pod\")", + ] + } + + output { + metrics = [otelcol.processor.batch.default.input] + logs = [otelcol.processor.batch.default.input] + traces = [otelcol.processor.batch.default.input] + } + } + + // Batch Processor + otelcol.processor.batch "default" { + send_batch_size = 8192 + send_batch_max_size = 0 + timeout = "2s" + + output { + metrics = [otelcol.processor.interval.default.input] + logs = [otelcol.processor.interval.default.input] + traces = [otelcol.processor.interval.default.input] + } + } + + // Interval Processor + otelcol.processor.interval "default" { + interval = "60s" + passthrough { + gauge = false + summary = false + } + + output { + metrics = argument.metrics_destinations.value + logs = argument.logs_destinations.value + traces = argument.traces_destinations.value + } + } + } diff --git a/grafana/charts/feature-application-observability/tests/__snapshot__/jaeger_test.yaml.snap b/grafana/charts/feature-application-observability/tests/__snapshot__/jaeger_test.yaml.snap new file mode 100644 index 0000000..0f4706e --- /dev/null +++ b/grafana/charts/feature-application-observability/tests/__snapshot__/jaeger_test.yaml.snap @@ -0,0 +1,476 @@ +should allow you to enable just the jaeger grpc receiver: + 1: | + |- + declare "application_observability" { + argument "metrics_destinations" { + comment = "Must be a list of metrics destinations where collected metrics should be forwarded to" + } + + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + argument "traces_destinations" { + comment = "Must be a list of trace destinations where collected trace should be forwarded to" + } + + // Jaeger Receiver + otelcol.receiver.jaeger "receiver" { + protocols { + grpc { + endpoint = "0.0.0.0:14250" + } + } + + debug_metrics { + disable_high_cardinality_metrics = true + } + output { + traces = [otelcol.processor.resourcedetection.default.input] + } + } + + // Resource Detection Processor + otelcol.processor.resourcedetection "default" { + detectors = ["env","system"] + override = true + + system { + hostname_sources = ["os"] + } + + output { + metrics = [otelcol.processor.k8sattributes.default.input] + logs = [otelcol.processor.k8sattributes.default.input] + traces = [otelcol.processor.k8sattributes.default.input] + } + } + + // K8s Attributes Processor + otelcol.processor.k8sattributes "default" { + extract { + metadata = ["k8s.namespace.name","k8s.pod.name","k8s.deployment.name","k8s.statefulset.name","k8s.daemonset.name","k8s.cronjob.name","k8s.job.name","k8s.node.name","k8s.pod.uid","k8s.pod.start_time"] + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.ip" + } + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.uid" + } + } + pod_association { + source { + from = "connection" + } + } + + output { + metrics = [otelcol.processor.transform.default.input] + logs = [otelcol.processor.transform.default.input] + traces = [otelcol.processor.transform.default.input, otelcol.connector.host_info.default.input] + } + } + + // Host Info Connector + otelcol.connector.host_info "default" { + host_identifiers = [ "k8s.node.name" ] + + output { + metrics = [otelcol.processor.batch.default.input] + } + } + + // Transform Processor + otelcol.processor.transform "default" { + error_mode = "ignore" + log_statements { + context = "resource" + statements = [ + "set(attributes[\"pod\"], attributes[\"k8s.pod.name\"])", + "set(attributes[\"namespace\"], attributes[\"k8s.namespace.name\"])", + "set(attributes[\"loki.resource.labels\"], \"cluster, namespace, job, pod\")", + ] + } + + output { + metrics = [otelcol.processor.batch.default.input] + logs = [otelcol.processor.batch.default.input] + traces = [otelcol.processor.batch.default.input] + } + } + + // Batch Processor + otelcol.processor.batch "default" { + send_batch_size = 8192 + send_batch_max_size = 0 + timeout = "2s" + + output { + metrics = argument.metrics_destinations.value + logs = argument.logs_destinations.value + traces = argument.traces_destinations.value + } + } + } +should allow you to enable just the jaeger thrift binary receiver: + 1: | + |- + declare "application_observability" { + argument "metrics_destinations" { + comment = "Must be a list of metrics destinations where collected metrics should be forwarded to" + } + + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + argument "traces_destinations" { + comment = "Must be a list of trace destinations where collected trace should be forwarded to" + } + + // Jaeger Receiver + otelcol.receiver.jaeger "receiver" { + protocols { + thrift_binary { + endpoint = "0.0.0.0:6832" + } + } + + debug_metrics { + disable_high_cardinality_metrics = true + } + output { + traces = [otelcol.processor.resourcedetection.default.input] + } + } + + // Resource Detection Processor + otelcol.processor.resourcedetection "default" { + detectors = ["env","system"] + override = true + + system { + hostname_sources = ["os"] + } + + output { + metrics = [otelcol.processor.k8sattributes.default.input] + logs = [otelcol.processor.k8sattributes.default.input] + traces = [otelcol.processor.k8sattributes.default.input] + } + } + + // K8s Attributes Processor + otelcol.processor.k8sattributes "default" { + extract { + metadata = ["k8s.namespace.name","k8s.pod.name","k8s.deployment.name","k8s.statefulset.name","k8s.daemonset.name","k8s.cronjob.name","k8s.job.name","k8s.node.name","k8s.pod.uid","k8s.pod.start_time"] + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.ip" + } + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.uid" + } + } + pod_association { + source { + from = "connection" + } + } + + output { + metrics = [otelcol.processor.transform.default.input] + logs = [otelcol.processor.transform.default.input] + traces = [otelcol.processor.transform.default.input, otelcol.connector.host_info.default.input] + } + } + + // Host Info Connector + otelcol.connector.host_info "default" { + host_identifiers = [ "k8s.node.name" ] + + output { + metrics = [otelcol.processor.batch.default.input] + } + } + + // Transform Processor + otelcol.processor.transform "default" { + error_mode = "ignore" + log_statements { + context = "resource" + statements = [ + "set(attributes[\"pod\"], attributes[\"k8s.pod.name\"])", + "set(attributes[\"namespace\"], attributes[\"k8s.namespace.name\"])", + "set(attributes[\"loki.resource.labels\"], \"cluster, namespace, job, pod\")", + ] + } + + output { + metrics = [otelcol.processor.batch.default.input] + logs = [otelcol.processor.batch.default.input] + traces = [otelcol.processor.batch.default.input] + } + } + + // Batch Processor + otelcol.processor.batch "default" { + send_batch_size = 8192 + send_batch_max_size = 0 + timeout = "2s" + + output { + metrics = argument.metrics_destinations.value + logs = argument.logs_destinations.value + traces = argument.traces_destinations.value + } + } + } +should allow you to enable just the jaeger thrift compact receiver: + 1: | + |- + declare "application_observability" { + argument "metrics_destinations" { + comment = "Must be a list of metrics destinations where collected metrics should be forwarded to" + } + + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + argument "traces_destinations" { + comment = "Must be a list of trace destinations where collected trace should be forwarded to" + } + + // Jaeger Receiver + otelcol.receiver.jaeger "receiver" { + protocols { + thrift_compact { + endpoint = "0.0.0.0:6831" + } + } + + debug_metrics { + disable_high_cardinality_metrics = true + } + output { + traces = [otelcol.processor.resourcedetection.default.input] + } + } + + // Resource Detection Processor + otelcol.processor.resourcedetection "default" { + detectors = ["env","system"] + override = true + + system { + hostname_sources = ["os"] + } + + output { + metrics = [otelcol.processor.k8sattributes.default.input] + logs = [otelcol.processor.k8sattributes.default.input] + traces = [otelcol.processor.k8sattributes.default.input] + } + } + + // K8s Attributes Processor + otelcol.processor.k8sattributes "default" { + extract { + metadata = ["k8s.namespace.name","k8s.pod.name","k8s.deployment.name","k8s.statefulset.name","k8s.daemonset.name","k8s.cronjob.name","k8s.job.name","k8s.node.name","k8s.pod.uid","k8s.pod.start_time"] + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.ip" + } + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.uid" + } + } + pod_association { + source { + from = "connection" + } + } + + output { + metrics = [otelcol.processor.transform.default.input] + logs = [otelcol.processor.transform.default.input] + traces = [otelcol.processor.transform.default.input, otelcol.connector.host_info.default.input] + } + } + + // Host Info Connector + otelcol.connector.host_info "default" { + host_identifiers = [ "k8s.node.name" ] + + output { + metrics = [otelcol.processor.batch.default.input] + } + } + + // Transform Processor + otelcol.processor.transform "default" { + error_mode = "ignore" + log_statements { + context = "resource" + statements = [ + "set(attributes[\"pod\"], attributes[\"k8s.pod.name\"])", + "set(attributes[\"namespace\"], attributes[\"k8s.namespace.name\"])", + "set(attributes[\"loki.resource.labels\"], \"cluster, namespace, job, pod\")", + ] + } + + output { + metrics = [otelcol.processor.batch.default.input] + logs = [otelcol.processor.batch.default.input] + traces = [otelcol.processor.batch.default.input] + } + } + + // Batch Processor + otelcol.processor.batch "default" { + send_batch_size = 8192 + send_batch_max_size = 0 + timeout = "2s" + + output { + metrics = argument.metrics_destinations.value + logs = argument.logs_destinations.value + traces = argument.traces_destinations.value + } + } + } +should allow you to enable just the jaeger thrift http receiver: + 1: | + |- + declare "application_observability" { + argument "metrics_destinations" { + comment = "Must be a list of metrics destinations where collected metrics should be forwarded to" + } + + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + argument "traces_destinations" { + comment = "Must be a list of trace destinations where collected trace should be forwarded to" + } + + // Jaeger Receiver + otelcol.receiver.jaeger "receiver" { + protocols { + thrift_http { + endpoint = "0.0.0.0:14268" + } + } + + debug_metrics { + disable_high_cardinality_metrics = true + } + output { + traces = [otelcol.processor.resourcedetection.default.input] + } + } + + // Resource Detection Processor + otelcol.processor.resourcedetection "default" { + detectors = ["env","system"] + override = true + + system { + hostname_sources = ["os"] + } + + output { + metrics = [otelcol.processor.k8sattributes.default.input] + logs = [otelcol.processor.k8sattributes.default.input] + traces = [otelcol.processor.k8sattributes.default.input] + } + } + + // K8s Attributes Processor + otelcol.processor.k8sattributes "default" { + extract { + metadata = ["k8s.namespace.name","k8s.pod.name","k8s.deployment.name","k8s.statefulset.name","k8s.daemonset.name","k8s.cronjob.name","k8s.job.name","k8s.node.name","k8s.pod.uid","k8s.pod.start_time"] + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.ip" + } + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.uid" + } + } + pod_association { + source { + from = "connection" + } + } + + output { + metrics = [otelcol.processor.transform.default.input] + logs = [otelcol.processor.transform.default.input] + traces = [otelcol.processor.transform.default.input, otelcol.connector.host_info.default.input] + } + } + + // Host Info Connector + otelcol.connector.host_info "default" { + host_identifiers = [ "k8s.node.name" ] + + output { + metrics = [otelcol.processor.batch.default.input] + } + } + + // Transform Processor + otelcol.processor.transform "default" { + error_mode = "ignore" + log_statements { + context = "resource" + statements = [ + "set(attributes[\"pod\"], attributes[\"k8s.pod.name\"])", + "set(attributes[\"namespace\"], attributes[\"k8s.namespace.name\"])", + "set(attributes[\"loki.resource.labels\"], \"cluster, namespace, job, pod\")", + ] + } + + output { + metrics = [otelcol.processor.batch.default.input] + logs = [otelcol.processor.batch.default.input] + traces = [otelcol.processor.batch.default.input] + } + } + + // Batch Processor + otelcol.processor.batch "default" { + send_batch_size = 8192 + send_batch_max_size = 0 + timeout = "2s" + + output { + metrics = argument.metrics_destinations.value + logs = argument.logs_destinations.value + traces = argument.traces_destinations.value + } + } + } diff --git a/grafana/charts/feature-application-observability/tests/__snapshot__/memorylimiter_test.yaml.snap b/grafana/charts/feature-application-observability/tests/__snapshot__/memorylimiter_test.yaml.snap new file mode 100644 index 0000000..e9b7ef2 --- /dev/null +++ b/grafana/charts/feature-application-observability/tests/__snapshot__/memorylimiter_test.yaml.snap @@ -0,0 +1,126 @@ +creates the pipeline with the interval processor: + 1: | + |- + declare "application_observability" { + argument "metrics_destinations" { + comment = "Must be a list of metrics destinations where collected metrics should be forwarded to" + } + + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + argument "traces_destinations" { + comment = "Must be a list of trace destinations where collected trace should be forwarded to" + } + + // Zipkin Receiver + otelcol.receiver.zipkin "receiver" { + endpoint = "0.0.0.0:9411" + debug_metrics { + disable_high_cardinality_metrics = true + } + output { + traces = [otelcol.processor.memory_limiter.default.input] + } + } + + // Memory Limiter + otelcol.processor.memory_limiter "default" { + check_interval = "1s" + limit = "100MiB" + + output { + metrics = [otelcol.processor.resourcedetection.default.input] + logs = [otelcol.processor.resourcedetection.default.input] + traces = [otelcol.processor.resourcedetection.default.input] + } + } + + // Resource Detection Processor + otelcol.processor.resourcedetection "default" { + detectors = ["env","system"] + override = true + + system { + hostname_sources = ["os"] + } + + output { + metrics = [otelcol.processor.k8sattributes.default.input] + logs = [otelcol.processor.k8sattributes.default.input] + traces = [otelcol.processor.k8sattributes.default.input] + } + } + + // K8s Attributes Processor + otelcol.processor.k8sattributes "default" { + extract { + metadata = ["k8s.namespace.name","k8s.pod.name","k8s.deployment.name","k8s.statefulset.name","k8s.daemonset.name","k8s.cronjob.name","k8s.job.name","k8s.node.name","k8s.pod.uid","k8s.pod.start_time"] + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.ip" + } + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.uid" + } + } + pod_association { + source { + from = "connection" + } + } + + output { + metrics = [otelcol.processor.transform.default.input] + logs = [otelcol.processor.transform.default.input] + traces = [otelcol.processor.transform.default.input, otelcol.connector.host_info.default.input] + } + } + + // Host Info Connector + otelcol.connector.host_info "default" { + host_identifiers = [ "k8s.node.name" ] + + output { + metrics = [otelcol.processor.batch.default.input] + } + } + + // Transform Processor + otelcol.processor.transform "default" { + error_mode = "ignore" + log_statements { + context = "resource" + statements = [ + "set(attributes[\"pod\"], attributes[\"k8s.pod.name\"])", + "set(attributes[\"namespace\"], attributes[\"k8s.namespace.name\"])", + "set(attributes[\"loki.resource.labels\"], \"cluster, namespace, job, pod\")", + ] + } + + output { + metrics = [otelcol.processor.batch.default.input] + logs = [otelcol.processor.batch.default.input] + traces = [otelcol.processor.batch.default.input] + } + } + + // Batch Processor + otelcol.processor.batch "default" { + send_batch_size = 8192 + send_batch_max_size = 0 + timeout = "2s" + + output { + metrics = argument.metrics_destinations.value + logs = argument.logs_destinations.value + traces = argument.traces_destinations.value + } + } + } diff --git a/grafana/charts/feature-application-observability/tests/__snapshot__/resourcedetection_test.yaml.snap b/grafana/charts/feature-application-observability/tests/__snapshot__/resourcedetection_test.yaml.snap new file mode 100644 index 0000000..f2a6d0a --- /dev/null +++ b/grafana/charts/feature-application-observability/tests/__snapshot__/resourcedetection_test.yaml.snap @@ -0,0 +1,353 @@ +creates the pipeline with the default resource detection processor: + 1: | + |- + declare "application_observability" { + argument "metrics_destinations" { + comment = "Must be a list of metrics destinations where collected metrics should be forwarded to" + } + + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + argument "traces_destinations" { + comment = "Must be a list of trace destinations where collected trace should be forwarded to" + } + + // Zipkin Receiver + otelcol.receiver.zipkin "receiver" { + endpoint = "0.0.0.0:9411" + debug_metrics { + disable_high_cardinality_metrics = true + } + output { + traces = [otelcol.processor.resourcedetection.default.input] + } + } + + // Resource Detection Processor + otelcol.processor.resourcedetection "default" { + detectors = ["env","system"] + override = true + + system { + hostname_sources = ["os"] + } + + output { + metrics = [otelcol.processor.k8sattributes.default.input] + logs = [otelcol.processor.k8sattributes.default.input] + traces = [otelcol.processor.k8sattributes.default.input] + } + } + + // K8s Attributes Processor + otelcol.processor.k8sattributes "default" { + extract { + metadata = ["k8s.namespace.name","k8s.pod.name","k8s.deployment.name","k8s.statefulset.name","k8s.daemonset.name","k8s.cronjob.name","k8s.job.name","k8s.node.name","k8s.pod.uid","k8s.pod.start_time"] + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.ip" + } + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.uid" + } + } + pod_association { + source { + from = "connection" + } + } + + output { + metrics = [otelcol.processor.transform.default.input] + logs = [otelcol.processor.transform.default.input] + traces = [otelcol.processor.transform.default.input, otelcol.connector.host_info.default.input] + } + } + + // Host Info Connector + otelcol.connector.host_info "default" { + host_identifiers = [ "k8s.node.name" ] + + output { + metrics = [otelcol.processor.batch.default.input] + } + } + + // Transform Processor + otelcol.processor.transform "default" { + error_mode = "ignore" + log_statements { + context = "resource" + statements = [ + "set(attributes[\"pod\"], attributes[\"k8s.pod.name\"])", + "set(attributes[\"namespace\"], attributes[\"k8s.namespace.name\"])", + "set(attributes[\"loki.resource.labels\"], \"cluster, namespace, job, pod\")", + ] + } + + output { + metrics = [otelcol.processor.batch.default.input] + logs = [otelcol.processor.batch.default.input] + traces = [otelcol.processor.batch.default.input] + } + } + + // Batch Processor + otelcol.processor.batch "default" { + send_batch_size = 8192 + send_batch_max_size = 0 + timeout = "2s" + + output { + metrics = argument.metrics_destinations.value + logs = argument.logs_destinations.value + traces = argument.traces_destinations.value + } + } + } +creates the resource detection processor with EKS info: + 1: | + |- + declare "application_observability" { + argument "metrics_destinations" { + comment = "Must be a list of metrics destinations where collected metrics should be forwarded to" + } + + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + argument "traces_destinations" { + comment = "Must be a list of trace destinations where collected trace should be forwarded to" + } + + // Zipkin Receiver + otelcol.receiver.zipkin "receiver" { + endpoint = "0.0.0.0:9411" + debug_metrics { + disable_high_cardinality_metrics = true + } + output { + traces = [otelcol.processor.resourcedetection.default.input] + } + } + + // Resource Detection Processor + otelcol.processor.resourcedetection "default" { + detectors = ["eks","env","system"] + override = false + + eks { + resource_attributes { + k8s.cluster.name { enabled = true } + } + } + + system { + hostname_sources = ["os"] + } + + output { + metrics = [otelcol.processor.k8sattributes.default.input] + logs = [otelcol.processor.k8sattributes.default.input] + traces = [otelcol.processor.k8sattributes.default.input] + } + } + + // K8s Attributes Processor + otelcol.processor.k8sattributes "default" { + extract { + metadata = ["k8s.namespace.name","k8s.pod.name","k8s.deployment.name","k8s.statefulset.name","k8s.daemonset.name","k8s.cronjob.name","k8s.job.name","k8s.node.name","k8s.pod.uid","k8s.pod.start_time"] + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.ip" + } + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.uid" + } + } + pod_association { + source { + from = "connection" + } + } + + output { + metrics = [otelcol.processor.transform.default.input] + logs = [otelcol.processor.transform.default.input] + traces = [otelcol.processor.transform.default.input, otelcol.connector.host_info.default.input] + } + } + + // Host Info Connector + otelcol.connector.host_info "default" { + host_identifiers = [ "k8s.node.name" ] + + output { + metrics = [otelcol.processor.batch.default.input] + } + } + + // Transform Processor + otelcol.processor.transform "default" { + error_mode = "ignore" + log_statements { + context = "resource" + statements = [ + "set(attributes[\"pod\"], attributes[\"k8s.pod.name\"])", + "set(attributes[\"namespace\"], attributes[\"k8s.namespace.name\"])", + "set(attributes[\"loki.resource.labels\"], \"cluster, namespace, job, pod\")", + ] + } + + output { + metrics = [otelcol.processor.batch.default.input] + logs = [otelcol.processor.batch.default.input] + traces = [otelcol.processor.batch.default.input] + } + } + + // Batch Processor + otelcol.processor.batch "default" { + send_batch_size = 8192 + send_batch_max_size = 0 + timeout = "2s" + + output { + metrics = argument.metrics_destinations.value + logs = argument.logs_destinations.value + traces = argument.traces_destinations.value + } + } + } +creates the resource detection processor with Kubernetes node info: + 1: | + |- + declare "application_observability" { + argument "metrics_destinations" { + comment = "Must be a list of metrics destinations where collected metrics should be forwarded to" + } + + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + argument "traces_destinations" { + comment = "Must be a list of trace destinations where collected trace should be forwarded to" + } + + // Zipkin Receiver + otelcol.receiver.zipkin "receiver" { + endpoint = "0.0.0.0:9411" + debug_metrics { + disable_high_cardinality_metrics = true + } + output { + traces = [otelcol.processor.resourcedetection.default.input] + } + } + + // Resource Detection Processor + otelcol.processor.resourcedetection "default" { + detectors = ["env","kubernetesNode","system"] + override = true + + kubernetes_node { + auth_type = "serviceAccount" + node_from_env_var = "K8S_NODE_NAME" + } + + system { + hostname_sources = ["os"] + } + + output { + metrics = [otelcol.processor.k8sattributes.default.input] + logs = [otelcol.processor.k8sattributes.default.input] + traces = [otelcol.processor.k8sattributes.default.input] + } + } + + // K8s Attributes Processor + otelcol.processor.k8sattributes "default" { + extract { + metadata = ["k8s.namespace.name","k8s.pod.name","k8s.deployment.name","k8s.statefulset.name","k8s.daemonset.name","k8s.cronjob.name","k8s.job.name","k8s.node.name","k8s.pod.uid","k8s.pod.start_time"] + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.ip" + } + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.uid" + } + } + pod_association { + source { + from = "connection" + } + } + + output { + metrics = [otelcol.processor.transform.default.input] + logs = [otelcol.processor.transform.default.input] + traces = [otelcol.processor.transform.default.input, otelcol.connector.host_info.default.input] + } + } + + // Host Info Connector + otelcol.connector.host_info "default" { + host_identifiers = [ "k8s.node.name" ] + + output { + metrics = [otelcol.processor.batch.default.input] + } + } + + // Transform Processor + otelcol.processor.transform "default" { + error_mode = "ignore" + log_statements { + context = "resource" + statements = [ + "set(attributes[\"pod\"], attributes[\"k8s.pod.name\"])", + "set(attributes[\"namespace\"], attributes[\"k8s.namespace.name\"])", + "set(attributes[\"loki.resource.labels\"], \"cluster, namespace, job, pod\")", + ] + } + + output { + metrics = [otelcol.processor.batch.default.input] + logs = [otelcol.processor.batch.default.input] + traces = [otelcol.processor.batch.default.input] + } + } + + // Batch Processor + otelcol.processor.batch "default" { + send_batch_size = 8192 + send_batch_max_size = 0 + timeout = "2s" + + output { + metrics = argument.metrics_destinations.value + logs = argument.logs_destinations.value + traces = argument.traces_destinations.value + } + } + } diff --git a/grafana/charts/feature-application-observability/tests/__snapshot__/spanlogs_test.yaml.snap b/grafana/charts/feature-application-observability/tests/__snapshot__/spanlogs_test.yaml.snap new file mode 100644 index 0000000..5395eb5 --- /dev/null +++ b/grafana/charts/feature-application-observability/tests/__snapshot__/spanlogs_test.yaml.snap @@ -0,0 +1,145 @@ +creates the pipeline with the spanmetrics connector: + 1: | + |- + declare "application_observability" { + argument "metrics_destinations" { + comment = "Must be a list of metrics destinations where collected metrics should be forwarded to" + } + + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + argument "traces_destinations" { + comment = "Must be a list of trace destinations where collected trace should be forwarded to" + } + + // OTLP Receiver + otelcol.receiver.otlp "receiver" { + grpc { + endpoint = "0.0.0.0:4317" + max_recv_msg_size = "4MiB" + read_buffer_size = "512KiB" + write_buffer_size = "32KiB" + } + debug_metrics { + disable_high_cardinality_metrics = true + } + output { + metrics = [otelcol.processor.resourcedetection.default.input] + logs = [otelcol.processor.resourcedetection.default.input] + traces = [otelcol.processor.resourcedetection.default.input] + } + } + + // Resource Detection Processor + otelcol.processor.resourcedetection "default" { + detectors = ["env","system"] + override = true + + system { + hostname_sources = ["os"] + } + + output { + metrics = [otelcol.processor.k8sattributes.default.input] + logs = [otelcol.processor.k8sattributes.default.input] + traces = [otelcol.processor.k8sattributes.default.input] + } + } + + // K8s Attributes Processor + otelcol.processor.k8sattributes "default" { + extract { + metadata = ["k8s.namespace.name","k8s.pod.name","k8s.deployment.name","k8s.statefulset.name","k8s.daemonset.name","k8s.cronjob.name","k8s.job.name","k8s.node.name","k8s.pod.uid","k8s.pod.start_time"] + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.ip" + } + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.uid" + } + } + pod_association { + source { + from = "connection" + } + } + + output { + metrics = [otelcol.processor.transform.default.input] + logs = [otelcol.processor.transform.default.input] + traces = [otelcol.processor.transform.default.input, otelcol.connector.host_info.default.input] + } + } + + // Host Info Connector + otelcol.connector.host_info "default" { + host_identifiers = [ "k8s.node.name" ] + + output { + metrics = [otelcol.processor.batch.default.input] + } + } + + // Transform Processor + otelcol.processor.transform "default" { + error_mode = "ignore" + log_statements { + context = "resource" + statements = [ + "set(attributes[\"pod\"], attributes[\"k8s.pod.name\"])", + "set(attributes[\"namespace\"], attributes[\"k8s.namespace.name\"])", + "set(attributes[\"loki.resource.labels\"], \"cluster, namespace, job, pod\")", + ] + } + + output { + metrics = [otelcol.processor.batch.default.input] + logs = [otelcol.processor.batch.default.input] + traces = [otelcol.connector.spanlogs.default.input, otelcol.processor.batch.default.input] + } + } + + // Span Logs Connector + otelcol.connector.spanlogs "default" { + spans = true + + output { + logs = [otelcol.processor.batch.default.input] + } + } + + // Batch Processor + otelcol.processor.batch "default" { + send_batch_size = 8192 + send_batch_max_size = 0 + timeout = "2s" + + output { + metrics = [otelcol.processor.interval.default.input] + logs = [otelcol.processor.interval.default.input] + traces = [otelcol.processor.interval.default.input] + } + } + + // Interval Processor + otelcol.processor.interval "default" { + interval = "60s" + passthrough { + gauge = false + summary = false + } + + output { + metrics = argument.metrics_destinations.value + logs = argument.logs_destinations.value + traces = argument.traces_destinations.value + } + } + } diff --git a/grafana/charts/feature-application-observability/tests/__snapshot__/spanmetrics_test.yaml.snap b/grafana/charts/feature-application-observability/tests/__snapshot__/spanmetrics_test.yaml.snap new file mode 100644 index 0000000..db5c045 --- /dev/null +++ b/grafana/charts/feature-application-observability/tests/__snapshot__/spanmetrics_test.yaml.snap @@ -0,0 +1,161 @@ +creates the pipeline with the spanmetrics connector: + 1: | + |- + declare "application_observability" { + argument "metrics_destinations" { + comment = "Must be a list of metrics destinations where collected metrics should be forwarded to" + } + + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + argument "traces_destinations" { + comment = "Must be a list of trace destinations where collected trace should be forwarded to" + } + + // OTLP Receiver + otelcol.receiver.otlp "receiver" { + grpc { + endpoint = "0.0.0.0:4317" + max_recv_msg_size = "4MiB" + read_buffer_size = "512KiB" + write_buffer_size = "32KiB" + } + debug_metrics { + disable_high_cardinality_metrics = true + } + output { + metrics = [otelcol.processor.resourcedetection.default.input] + logs = [otelcol.processor.resourcedetection.default.input] + traces = [otelcol.processor.resourcedetection.default.input] + } + } + + // Resource Detection Processor + otelcol.processor.resourcedetection "default" { + detectors = ["env","system"] + override = true + + system { + hostname_sources = ["os"] + } + + output { + metrics = [otelcol.processor.k8sattributes.default.input] + logs = [otelcol.processor.k8sattributes.default.input] + traces = [otelcol.processor.k8sattributes.default.input] + } + } + + // K8s Attributes Processor + otelcol.processor.k8sattributes "default" { + extract { + metadata = ["k8s.namespace.name","k8s.pod.name","k8s.deployment.name","k8s.statefulset.name","k8s.daemonset.name","k8s.cronjob.name","k8s.job.name","k8s.node.name","k8s.pod.uid","k8s.pod.start_time"] + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.ip" + } + } + pod_association { + source { + from = "resource_attribute" + name = "k8s.pod.uid" + } + } + pod_association { + source { + from = "connection" + } + } + + output { + metrics = [otelcol.processor.transform.default.input] + logs = [otelcol.processor.transform.default.input] + traces = [otelcol.processor.transform.default.input, otelcol.connector.host_info.default.input] + } + } + + // Host Info Connector + otelcol.connector.host_info "default" { + host_identifiers = [ "k8s.node.name" ] + + output { + metrics = [otelcol.processor.batch.default.input] + } + } + + // Transform Processor + otelcol.processor.transform "default" { + error_mode = "ignore" + log_statements { + context = "resource" + statements = [ + "set(attributes[\"pod\"], attributes[\"k8s.pod.name\"])", + "set(attributes[\"namespace\"], attributes[\"k8s.namespace.name\"])", + "set(attributes[\"loki.resource.labels\"], \"cluster, namespace, job, pod\")", + ] + } + + output { + metrics = [otelcol.processor.batch.default.input] + logs = [otelcol.processor.batch.default.input] + traces = [otelcol.connector.spanmetrics.default.input, otelcol.processor.batch.default.input] + } + } + + // Span Metrics Connector + otelcol.connector.spanmetrics "default" { + dimension { + name = "http.status_code" + } + dimension { + name = "http.method" + default = "GET" + } + dimensions_cache_size = 1000 + namespace = "traces.span.metrics" + + histogram { + disable = false + unit = "ms" + explicit { + buckets = ["2ms","4ms","6ms","8ms","10ms","50ms","100ms","200ms","400ms","800ms","1s","1400ms","2s","5s","10s","15s"] + } + } + + output { + metrics = [otelcol.processor.batch.default.input] + } + } + + // Batch Processor + otelcol.processor.batch "default" { + send_batch_size = 8192 + send_batch_max_size = 0 + timeout = "2s" + + output { + metrics = [otelcol.processor.interval.default.input] + logs = [otelcol.processor.interval.default.input] + traces = [otelcol.processor.interval.default.input] + } + } + + // Interval Processor + otelcol.processor.interval "default" { + interval = "60s" + passthrough { + gauge = false + summary = false + } + + output { + metrics = argument.metrics_destinations.value + logs = argument.logs_destinations.value + traces = argument.traces_destinations.value + } + } + } diff --git a/grafana/charts/feature-application-observability/tests/default_test.yaml b/grafana/charts/feature-application-observability/tests/default_test.yaml new file mode 100644 index 0000000..d06224a --- /dev/null +++ b/grafana/charts/feature-application-observability/tests/default_test.yaml @@ -0,0 +1,30 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test default values +templates: + - configmap.yaml +tests: + - it: creates the default pipeline + set: + deployAsConfigMap: true + receivers: + otlp: + grpc: + enabled: true + http: + enabled: true + jaeger: + grpc: + enabled: true + thriftBinary: + enabled: true + thriftCompact: + enabled: true + thriftHttp: + enabled: true + zipkin: + enabled: true + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] diff --git a/grafana/charts/feature-application-observability/tests/interval_test.yaml b/grafana/charts/feature-application-observability/tests/interval_test.yaml new file mode 100644 index 0000000..978649b --- /dev/null +++ b/grafana/charts/feature-application-observability/tests/interval_test.yaml @@ -0,0 +1,33 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test with interval processor +templates: + - configmap.yaml +tests: + - it: creates the pipeline with the interval processor + set: + deployAsConfigMap: true + processors: + interval: + enabled: true + receivers: + otlp: + grpc: + enabled: true + http: + enabled: true + jaeger: + grpc: + enabled: true + thriftBinary: + enabled: true + thriftCompact: + enabled: true + thriftHttp: + enabled: true + zipkin: + enabled: true + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] diff --git a/grafana/charts/feature-application-observability/tests/jaeger_test.yaml b/grafana/charts/feature-application-observability/tests/jaeger_test.yaml new file mode 100644 index 0000000..54b4a61 --- /dev/null +++ b/grafana/charts/feature-application-observability/tests/jaeger_test.yaml @@ -0,0 +1,57 @@ +--- +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces rule:empty-lines +suite: Test Loki integration +templates: + - configmap.yaml +tests: + - it: should allow you to enable just the jaeger grpc receiver + set: + deployAsConfigMap: true + receivers: + jaeger: + grpc: + enabled: true + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] + + - it: should allow you to enable just the jaeger thrift binary receiver + set: + deployAsConfigMap: true + receivers: + jaeger: + thriftBinary: + enabled: true + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] + + - it: should allow you to enable just the jaeger thrift compact receiver + set: + deployAsConfigMap: true + receivers: + jaeger: + thriftCompact: + enabled: true + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] + + - it: should allow you to enable just the jaeger thrift http receiver + set: + deployAsConfigMap: true + receivers: + jaeger: + thriftHttp: + enabled: true + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] diff --git a/grafana/charts/feature-application-observability/tests/memorylimiter_test.yaml b/grafana/charts/feature-application-observability/tests/memorylimiter_test.yaml new file mode 100644 index 0000000..b467f23 --- /dev/null +++ b/grafana/charts/feature-application-observability/tests/memorylimiter_test.yaml @@ -0,0 +1,20 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test with interval processor +templates: + - configmap.yaml +tests: + - it: creates the pipeline with the interval processor + set: + deployAsConfigMap: true + processors: + memoryLimiter: + enabled: true + limit: 100MiB + receivers: + zipkin: + enabled: true + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] diff --git a/grafana/charts/feature-application-observability/tests/resourcedetection_test.yaml b/grafana/charts/feature-application-observability/tests/resourcedetection_test.yaml new file mode 100644 index 0000000..969442e --- /dev/null +++ b/grafana/charts/feature-application-observability/tests/resourcedetection_test.yaml @@ -0,0 +1,52 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test with resource detection processor +templates: + - configmap.yaml +tests: + - it: creates the pipeline with the default resource detection processor + set: + deployAsConfigMap: true + receivers: + zipkin: + enabled: true + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] + + - it: creates the resource detection processor with Kubernetes node info + set: + deployAsConfigMap: true + processors: + resourceDetection: + kubernetesNode: + enabled: true + receivers: + zipkin: + enabled: true + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] + + - it: creates the resource detection processor with EKS info + set: + deployAsConfigMap: true + processors: + resourceDetection: + override: false + eks: + enabled: true + resourceAttributes: + k8s.cluster.name: + enabled: true + receivers: + zipkin: + enabled: true + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] diff --git a/grafana/charts/feature-application-observability/tests/spanlogs_test.yaml b/grafana/charts/feature-application-observability/tests/spanlogs_test.yaml new file mode 100644 index 0000000..cd9e647 --- /dev/null +++ b/grafana/charts/feature-application-observability/tests/spanlogs_test.yaml @@ -0,0 +1,24 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test with spanmetrics processor +templates: + - configmap.yaml +tests: + - it: creates the pipeline with the spanmetrics connector + set: + deployAsConfigMap: true + processors: + interval: + enabled: true + connectors: + spanLogs: + enabled: true + spans: true + receivers: + otlp: + grpc: + enabled: true + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] diff --git a/grafana/charts/feature-application-observability/tests/spanmetrics_test.yaml b/grafana/charts/feature-application-observability/tests/spanmetrics_test.yaml new file mode 100644 index 0000000..aed84fc --- /dev/null +++ b/grafana/charts/feature-application-observability/tests/spanmetrics_test.yaml @@ -0,0 +1,27 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test with spanmetrics processor +templates: + - configmap.yaml +tests: + - it: creates the pipeline with the spanmetrics connector + set: + deployAsConfigMap: true + processors: + interval: + enabled: true + connectors: + spanMetrics: + enabled: true + dimensions: + - name: "http.status_code" + - name: "http.method" + default: "GET" + receivers: + otlp: + grpc: + enabled: true + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] diff --git a/grafana/charts/feature-application-observability/tests/validation_test.yaml b/grafana/charts/feature-application-observability/tests/validation_test.yaml new file mode 100644 index 0000000..5795cbf --- /dev/null +++ b/grafana/charts/feature-application-observability/tests/validation_test.yaml @@ -0,0 +1,20 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test validation +templates: + - configmap.yaml +tests: + - it: requires at least one receiver + set: + deployAsConfigMap: true + asserts: + - failedTemplate: + errorMessage: |- + execution error at (feature-application-observability/templates/configmap.yaml:2:4): + At least one receiver must be enabled to use Application Observability. + Please enable one. For example: + applicationObservability: + receivers: + otlp: + grpc: + enabled: true + See https://github.com/grafana/k8s-monitoring-helm/tree/main/charts/k8s-monitoring/charts/feature-application-observability for more details. diff --git a/grafana/charts/feature-application-observability/values.schema.json b/grafana/charts/feature-application-observability/values.schema.json new file mode 100644 index 0000000..4e35bf8 --- /dev/null +++ b/grafana/charts/feature-application-observability/values.schema.json @@ -0,0 +1,461 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "connectors": { + "type": "object", + "properties": { + "grafanaCloudMetrics": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "spanLogs": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "labels": { + "type": "array" + }, + "process": { + "type": "boolean" + }, + "processAttributes": { + "type": "array" + }, + "roots": { + "type": "boolean" + }, + "spanAttributes": { + "type": "array" + }, + "spans": { + "type": "boolean" + } + } + }, + "spanMetrics": { + "type": "object", + "properties": { + "dimensions": { + "type": "array" + }, + "dimensionsCacheSize": { + "type": "integer" + }, + "enabled": { + "type": "boolean" + }, + "events": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "exemplars": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "maxPerDataPoint": { + "type": "null" + } + } + }, + "histogram": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "explicit": { + "type": "object", + "properties": { + "buckets": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "exponential": { + "type": "object", + "properties": { + "maxSize": { + "type": "integer" + } + } + }, + "type": { + "type": "string", + "enum": [ + "explicit", + "exponential" + ] + }, + "unit": { + "type": "string" + } + } + }, + "namespace": { + "type": "string" + } + } + } + } + }, + "deployAsConfigMap": { + "type": "boolean" + }, + "fullnameOverride": { + "type": "string" + }, + "logs": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "filters": { + "type": "object", + "properties": { + "log_record": { + "type": "array" + } + } + }, + "transforms": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "log": { + "type": "array" + }, + "resource": { + "type": "array" + } + } + } + } + }, + "metrics": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "filters": { + "type": "object", + "properties": { + "datapoint": { + "type": "array" + }, + "metric": { + "type": "array" + } + } + }, + "transforms": { + "type": "object", + "properties": { + "datapoint": { + "type": "array" + }, + "metric": { + "type": "array" + }, + "resource": { + "type": "array" + } + } + } + } + }, + "nameOverride": { + "type": "string" + }, + "processors": { + "type": "object", + "properties": { + "batch": { + "type": "object", + "properties": { + "maxSize": { + "type": "integer" + }, + "size": { + "type": "integer" + }, + "timeout": { + "type": "string" + } + } + }, + "interval": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "interval": { + "type": "string" + }, + "passthrough": { + "type": "object", + "properties": { + "gauge": { + "type": "boolean" + }, + "summary": { + "type": "boolean" + } + } + } + } + }, + "k8sattributes": { + "type": "object", + "properties": { + "annotations": { + "type": "array" + }, + "labels": { + "type": "array" + }, + "metadata": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "memoryLimiter": { + "type": "object", + "properties": { + "checkInterval": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "limit": { + "type": "string" + } + } + }, + "resourceDetection": { + "type": "object", + "properties": { + "env": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "kubernetesNode": { + "type": "object", + "properties": { + "authType": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "nodeFromEnvVar": { + "type": "string" + } + } + }, + "override": { + "type": "boolean" + }, + "system": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "hostnameSources": { + "type": "array", + "items": { + "type": "string" + } + }, + "resourceAttributes": { + "type": "object" + } + } + } + } + } + } + }, + "receivers": { + "type": "object", + "properties": { + "jaeger": { + "type": "object", + "properties": { + "grpc": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "port": { + "type": "integer" + } + } + }, + "includeDebugMetrics": { + "type": "boolean" + }, + "thriftBinary": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "port": { + "type": "integer" + } + } + }, + "thriftCompact": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "port": { + "type": "integer" + } + } + }, + "thriftHttp": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "port": { + "type": "integer" + } + } + } + } + }, + "otlp": { + "type": "object", + "properties": { + "grpc": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "maxConcurrentStreams": { + "type": "integer" + }, + "maxReceivedMessageSize": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "readBufferSize": { + "type": "string" + }, + "writeBufferSize": { + "type": "string" + } + } + }, + "http": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "maxRequestBodySize": { + "type": "string" + }, + "port": { + "type": "integer" + } + } + }, + "includeDebugMetrics": { + "type": "boolean" + } + } + }, + "zipkin": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "includeDebugMetrics": { + "type": "boolean" + }, + "port": { + "type": "integer" + } + } + } + } + }, + "traces": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "filters": { + "type": "object", + "properties": { + "span": { + "type": "array" + }, + "spanevent": { + "type": "array" + } + } + }, + "transforms": { + "type": "object", + "properties": { + "resource": { + "type": "array" + }, + "span": { + "type": "array" + }, + "spanevent": { + "type": "array" + } + } + } + } + } + } +} diff --git a/grafana/charts/feature-application-observability/values.yaml b/grafana/charts/feature-application-observability/values.yaml new file mode 100644 index 0000000..b1c1e31 --- /dev/null +++ b/grafana/charts/feature-application-observability/values.yaml @@ -0,0 +1,350 @@ +--- +# -- Name override +# @section -- General settings +nameOverride: "" + +# -- Full name override +# @section -- General settings +fullnameOverride: "" + +receivers: + otlp: + # The OTLP gRPC receiver configuration. + grpc: + # -- Accept application data over OTLP gRPC. + # @section -- Receivers: OTLP + enabled: false + + # -- The port to listen on for OTLP gRPC requests. + # @section -- Receivers: OTLP + port: 4317 + + # -- Maximum size of messages the gRPC server will accept. + # @section -- Receivers: OTLP + maxReceivedMessageSize: 4MiB + + # -- Limit the number of concurrent streaming gRPC calls. 0 means no limit. + # @section -- Receivers: OTLP + maxConcurrentStreams: 0 + + # -- Size of the read buffer the gRPC server will use for reading from clients. + # @section -- Receivers: OTLP + readBufferSize: 512KiB + + # -- Size of the write buffer the gRPC server will use for writing to clients. + # @section -- Receivers: OTLP + writeBufferSize: 32KiB + + # The OTLP HTTP receiver configuration. + http: + # -- Accept application data over OTLP HTTP. + # @section -- Receivers: OTLP + enabled: false + + # -- The port to listen on for OTLP HTTP requests. + # @section -- Receivers: OTLP + port: 4318 + + # -- Maximum request body size the server will allow. + # @section -- Receivers: OTLP + maxRequestBodySize: 20MiB + + # -- Whether to include high-cardinality debug metrics. + # @section -- Receivers: OTLP + includeDebugMetrics: false + + jaeger: + # -- Configuration for the Jaeger receiver using the gRPC protocol. + # @section -- Receivers: Jaeger + grpc: + enabled: false + port: 14250 + + # -- Configuration for the Jaeger receiver using the Thrift binary protocol. + # @section -- Receivers: Jaeger + thriftBinary: + enabled: false + port: 6832 + + # -- Configuration for the Jaeger receiver using the Thrift compact protocol. + # @section -- Receivers: Jaeger + thriftCompact: + enabled: false + port: 6831 + + # -- Configuration for the Jaeger receiver using the Thrift HTTP protocol. + # @section -- Receivers: Jaeger + thriftHttp: + enabled: false + port: 14268 + + # -- Whether to include high-cardinality debug metrics. + # @section -- Receivers: Jaeger + includeDebugMetrics: false + + # -- The Zipkin receiver configuration. + # @section -- Receivers: Zipkin + zipkin: + enabled: false + port: 9411 + + # -- Whether to include high-cardinality debug metrics. + # @section -- Receivers: Zipkin + includeDebugMetrics: false + +# Processors are components that modify the telemetry data, such as filtering, batching, and adding metadata. +processors: + batch: + # -- What batch size to use + # @section -- Processors: Batch + size: 8192 + # -- The upper limit of the amount of data contained in a single batch. When set to 0, batches can be any size. + # @section -- Processors: Batch + maxSize: 0 + # -- How long before sending (Processors) + # @section -- Processors: Batch + timeout: 2s + + interval: + # -- Utilize an interval processor to aggregate metrics and periodically forward the latest values to the next + # component in the pipeline. + # @section -- Processors: Interval + enabled: false + + # -- The interval at which to emit aggregated metrics. + # @section -- Processors: Interval + interval: 60s + + passthrough: + # -- Determines whether gauge metrics should be passed through as they are or aggregated. + # @section -- Processors: Interval + gauge: false + + # -- Determines whether summary metrics should be passed through as they are or aggregated. + # @section -- Processors: Interval + summary: false + + # Capture Resource attributes from various sources. You can add more than is listed here. For example: + # resourceDetection: + # sourceType: + # enabled: true + # resourceAttributes: + # host.name: + # enabled: true + # @section -- Processors: Resource Detection + resourceDetection: + # -- Configures whether existing resource attributes should be overridden or preserved. + # @section -- Processors: Resource Detection + override: true + + env: + # -- Enable getting resource attributes from the OTEL_RESOURCE_ATTRIBUTES environment variable. + # @section -- Processors: Resource Detection + enabled: true + + system: + # -- Enable getting resource attributes from the host machine. + # @section -- Processors: Resource Detection + enabled: true + # -- The priority list of sources from which the hostname will be determined. Options: ["dns", "os", "cname", "lookup"]. + # @section -- Processors: Resource Detection + hostnameSources: + - os + # -- The list of resource attributes to add for system resource detection. See the + # [Alloy documentation](https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.resourcedetection/#system--resource_attributes) + # for a list of available attributes. + # @section -- Processors: Resource Detection + resourceAttributes: {} + + kubernetesNode: + # -- Enable getting resource attributes about the Kubernetes node from the API server. + # @section -- Processors: Resource Detection + enabled: false + + # -- The authentication method. This should not be changed. + # @section -- Processors: Resource Detection + authType: serviceAccount + + # -- The name of an environment variable from which to retrieve the node name. + # @section -- Processors: Resource Detection + nodeFromEnvVar: K8S_NODE_NAME + + k8sattributes: + # -- Kubernetes metadata to extract and add to the attributes of the received telemetry data. + # @section -- Processors: K8s Attributes + metadata: + - k8s.namespace.name + - k8s.pod.name + - k8s.deployment.name + - k8s.statefulset.name + - k8s.daemonset.name + - k8s.cronjob.name + - k8s.job.name + - k8s.node.name + - k8s.pod.uid + - k8s.pod.start_time + + # -- Kubernetes labels to extract and add to the attributes of the received telemetry data. + # @section -- Processors: K8s Attributes + labels: [] + + # -- Kubernetes annotations to extract and add to the attributes of the received telemetry data. + # @section -- Processors: K8s Attributes + annotations: [] + + memoryLimiter: + # -- Use a memory limiter. + # @section -- Processors: Memory Limiter + enabled: false + # -- How often to check memory usage. + # @section -- Processors: Memory Limiter + checkInterval: 1s + # -- Maximum amount of memory targeted to be allocated by the process heap. + # @section -- Processors: Memory Limiter + limit: 0MiB + +# Connectors are components that create new telemetry data from existing telemetry data. +connectors: + grafanaCloudMetrics: + # -- Generate host info metrics from telemetry data. These metrics are required for using Application Observability + # in Grafana Cloud. Note: Enabling this may incur additional costs. + # See [Application Observability Pricing](https://grafana.com/docs/grafana-cloud/monitor-applications/application-observability/pricing/) + # @section -- Connectors: Grafana Cloud Host Info + enabled: true + + # Span Logs connector settings. + spanLogs: + # -- Use a span logs connector which creates logs from spans. + # @section -- Connectors: Span Logs + enabled: false + + # -- Create a log line for each span. This can lead to a large number of logs. + # @section -- Connectors: Span Logs + spans: false + # -- Additional span attributes to log. + # @section -- Connectors: Span Logs + spanAttributes: [] + + # -- Log one line for every root span of a trace. + # @section -- Connectors: Span Logs + roots: false + + # -- Log one line for every process. + # @section -- Connectors: Span Logs + process: false + # -- Additional process attributes to log. + # @section -- Connectors: Span Logs + processAttributes: [] + + # -- A list of keys that will be logged as labels. + # @section -- Connectors: Span Logs + labels: [] + + # Span Metrics connector settings. + spanMetrics: + # -- Use a span metrics connector which creates metrics from spans. + # @section -- Connectors: Span Metrics + enabled: false + + # -- Define dimensions to be added. + # Some are set internally by default: [service.name, span.name, span.kind, status.code] + # Example: + # - name: "http.status_code" + # - name: "http.method" + # default: "GET" + # @section -- Connectors: Span Metrics + dimensions: [] + + # -- How many dimensions to cache + # @section -- Connectors: Span Metrics + dimensionsCacheSize: 1000 + + # -- The Metric namespace. + # @section -- Connectors: Span Metrics + namespace: traces.span.metrics + + events: + # -- Capture events metrics, which track span events. + # @section -- Connectors: Span Metrics + enabled: false + + exemplars: + # -- Attach exemplars to histograms. + # @section -- Connectors: Span Metrics + enabled: false + + # -- (number) Limits the number of exemplars that can be added to a unique dimension set. + # @section -- Connectors: Span Metrics + maxPerDataPoint: + + histogram: + # -- Capture histogram metrics, derived from spans’ durations. + # @section -- Connectors: Span Metrics + enabled: true + + # -- Type of histograms to create. Must be either "explicit" or "exponential". + # @section -- Connectors: Span Metrics + type: explicit + + # -- The histogram unit. + # @section -- Connectors: Span Metrics + unit: ms + + # Settings for explicit histograms. + explicit: + # -- The histogram buckets to use. + # @section -- Connectors: Span Metrics + buckets: ["2ms", "4ms", "6ms", "8ms", "10ms", "50ms", "100ms", "200ms", "400ms", "800ms", "1s", "1400ms", "2s", "5s", "10s", "15s"] + + # Settings for exponential histograms. + exponential: + # -- Maximum number of buckets per positive or negative number range. + # @section -- Connectors: Span Metrics + maxSize: 160 + +metrics: + enabled: true + # -- Apply a filter to metrics received via the OTLP or OTLP HTTP receivers. + # ([docs](https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.filter/)) + filters: + metric: [] + datapoint: [] + # -- Apply a transformation to metrics received via the OTLP or OTLP HTTP receivers. + # ([docs](https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.transform/)) + transforms: + resource: [] + metric: [] + datapoint: [] + +logs: + enabled: true + # -- Apply a filter to logs received via receivers. + # ([docs](https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.filter/)) + filters: + log_record: [] + # -- Apply a transformation to logs received via the OTLP or OTLP HTTP receivers. + # ([docs](https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.transform/)) + transforms: + # -- Resource transformation rules. + resource: [] + # -- Log transformation rules. + log: [] + # -- The list of labels to set in the log stream. + labels: ["cluster", "namespace", "job", "pod"] + +traces: + enabled: true + # -- Apply a filter to traces received via the OTLP or OTLP HTTP receivers. + # ([docs](https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.filter/)) + filters: + span: [] + spanevent: [] + # -- Apply a transformation to traces received via the OTLP or OTLP HTTP receivers. + # ([docs](https://grafana.com/docs/alloy/latest/reference/components/otelcol/otelcol.processor.transform/)) + transforms: + resource: [] + span: [] + spanevent: [] + +# @ignore +deployAsConfigMap: false diff --git a/grafana/charts/feature-auto-instrumentation/.helmignore b/grafana/charts/feature-auto-instrumentation/.helmignore new file mode 100644 index 0000000..2b29eaf --- /dev/null +++ b/grafana/charts/feature-auto-instrumentation/.helmignore @@ -0,0 +1,6 @@ +docs +schema-mods +tests +Makefile +README.md +README.md.gotmpl diff --git a/grafana/charts/feature-auto-instrumentation/Chart.lock b/grafana/charts/feature-auto-instrumentation/Chart.lock new file mode 100644 index 0000000..0fff476 --- /dev/null +++ b/grafana/charts/feature-auto-instrumentation/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: beyla + repository: https://grafana.github.io/helm-charts + version: 1.7.3 +digest: sha256:e67b8d0fbdd6fa7c09916ee2d5b64ad61d543ed72738966a0da818e88574a64f +generated: "2025-02-24T20:08:13.331063-06:00" diff --git a/grafana/charts/feature-auto-instrumentation/Chart.yaml b/grafana/charts/feature-auto-instrumentation/Chart.yaml new file mode 100644 index 0000000..344ced5 --- /dev/null +++ b/grafana/charts/feature-auto-instrumentation/Chart.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: v2 +name: feature-auto-instrumentation +description: Gathers telemetry data via automatic instrumentation +icon: https://raw.githubusercontent.com/grafana/grafana/main/public/img/grafana_icon.svg +sources: + - https://github.com/grafana/k8s-monitoring-helm/tree/main/charts/k8s-monitoring/charts/feature-annotation-autodiscovery +version: 1.0.0 +appVersion: 1.0.0 +maintainers: + - email: pete.wall@grafana.com + name: petewall +dependencies: + - name: beyla + version: 1.7.3 + repository: https://grafana.github.io/helm-charts + condition: beyla.enabled diff --git a/grafana/charts/feature-auto-instrumentation/Makefile b/grafana/charts/feature-auto-instrumentation/Makefile new file mode 100644 index 0000000..e32e8bc --- /dev/null +++ b/grafana/charts/feature-auto-instrumentation/Makefile @@ -0,0 +1,36 @@ +HAS_HELM_DOCS := $(shell command -v helm-docs;) +HAS_HELM_UNITTEST := $(shell helm plugin list | grep unittest 2> /dev/null) + +.SECONDEXPANSION: +README.md: values.yaml Chart.yaml $$(wildcard README.md.gotmpl) +ifdef HAS_HELM_DOCS + helm-docs +else + docker run --rm --volume "$(shell pwd):/helm-docs" -u $(shell id -u) jnorwood/helm-docs:latest +endif + +Chart.lock: Chart.yaml + helm dependency update . + @touch Chart.lock # Ensure the timestamp is updated + +values.schema.json: values.yaml $$(wildcard schema-mods/*) + ../../../../scripts/schema-gen.sh . + +.PHONY: clean +clean: + rm -f README.md values.schema.json + +.PHONY: build +build: README.md Chart.lock values.schema.json + +.PHONY: test +test: build + helm repo add grafana https://grafana.github.io/helm-charts + + helm lint . + ct lint --lint-conf ../../../../.configs/lintconf.yaml --helm-dependency-extra-args=--skip-refresh --charts . +ifdef HAS_HELM_UNITTEST + helm unittest . +else + docker run --rm --volume $(shell pwd):/apps helmunittest/helm-unittest:3.17.0-0.7.1 . +endif diff --git a/grafana/charts/feature-auto-instrumentation/README.md b/grafana/charts/feature-auto-instrumentation/README.md new file mode 100644 index 0000000..7a35deb --- /dev/null +++ b/grafana/charts/feature-auto-instrumentation/README.md @@ -0,0 +1,74 @@ + + +# feature-auto-instrumentation + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) +Gathers telemetry data via automatic instrumentation + +The auto-instrumentation feature deploys Grafana Beyla to automatically instrument programs running on this cluster using eBPF. + +## Testing + +This chart contains unit tests to verify the generated configuration. The hidden value `deployAsConfigMap` will render +the generated configuration into a ConfigMap object. While this ConfigMap is not used during regular operation, you can +use it to show the outcome of a given values file. + +The unit tests use this ConfigMap to create an object with the configuration that can be asserted against. To run the +tests, use `helm test`. + +Be sure perform actual integration testing in a live environment in the main [k8s-monitoring](../..) chart. + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| petewall | | | + + +## Source Code + +* + +## Requirements + +| Repository | Name | Version | +|------------|------|---------| +| https://grafana.github.io/helm-charts | beyla | 1.7.3 | + + + +## Values + +### Beyla + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| beyla.config.data | object | `{"attributes":{"kubernetes":{"enable":true}},"internal_metrics":{"prometheus":{"path":"/internal/metrics"}},"prometheus_export":{"features":["application","network","application_service_graph","application_span"],"path":"/metrics"}}` | The configuration for Grafana Beyla Some sections will be set automatically, such as the cluster name. Others will be modified depending on the value of beyla.preset. | +| beyla.extraDiscoveryRules | string | `""` | Rule blocks to be added to the discovery.relabel component for Beyla. These relabeling rules are applied pre-scrape against the targets from service discovery. Before the scrape, any remaining target labels that start with __ (i.e. __meta_kubernetes*) are dropped. ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery.relabel/#rule-block)) | +| beyla.extraMetricProcessingRules | string | `""` | Rule blocks to be added to the prometheus.relabel component for Beyla. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus.relabel/#rule-block)) These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no __meta* labels are present. | +| beyla.labelMatchers | object | `{"app.kubernetes.io/name":"beyla"}` | Label matchers used to select the Beyla pods for scraping metrics. | +| beyla.maxCacheSize | string | 100000 | Sets the max_cache_size for the prometheus.relabel component for Beyla. This should be at least 2x-5x your largest scrape target or samples appended rate. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus.relabel/#arguments)) Overrides metrics.maxCacheSize | +| beyla.metricsTuning.excludeMetrics | list | `[]` | Metrics to drop. Can use regular expressions. | +| beyla.metricsTuning.includeMetrics | list | `[]` | Metrics to keep. Can use regular expressions. | +| beyla.preset | string | `"application"` | The configuration preset to use. Valid options are "application" or "network". | +| beyla.scrapeInterval | string | 60s | How frequently to scrape metrics from Beyla. Overrides metrics.scrapeInterval | +| beyla.service | object | `{"targetPort":9090}` | The port number for the Beyla service. | + +### General settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| fullnameOverride | string | `""` | Full name override | +| nameOverride | string | `""` | Name override | + +### Global Settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| global.maxCacheSize | int | `100000` | Sets the max_cache_size for every prometheus.relabel component. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus.relabel/#arguments)) This should be at least 2x-5x your largest scrape target or samples appended rate. | +| global.platform | string | `""` | The specific platform for this cluster. Will enable compatibility for some platforms. Supported options: (empty) or "openshift". | +| global.scrapeInterval | string | `"60s"` | How frequently to scrape metrics. | + diff --git a/grafana/charts/feature-auto-instrumentation/README.md.gotmpl b/grafana/charts/feature-auto-instrumentation/README.md.gotmpl new file mode 100644 index 0000000..72ff780 --- /dev/null +++ b/grafana/charts/feature-auto-instrumentation/README.md.gotmpl @@ -0,0 +1,35 @@ + + +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} +{{ template "chart.badgesSection" . }} +{{ template "chart.description" . }} +{{ template "chart.homepageLine" . }} + +The auto-instrumentation feature deploys Grafana Beyla to automatically instrument programs running on this cluster using eBPF. + +## Testing + +This chart contains unit tests to verify the generated configuration. The hidden value `deployAsConfigMap` will render +the generated configuration into a ConfigMap object. While this ConfigMap is not used during regular operation, you can +use it to show the outcome of a given values file. + +The unit tests use this ConfigMap to create an object with the configuration that can be asserted against. To run the +tests, use `helm test`. + +Be sure perform actual integration testing in a live environment in the main [k8s-monitoring](../..) chart. + +{{ template "chart.maintainersSection" . }} + + +{{ template "chart.sourcesSection" . }} + +{{ template "chart.requirementsSection" . }} + + + +{{ template "chart.valuesSection" . }} + diff --git a/grafana/charts/feature-auto-instrumentation/charts/beyla-1.7.3.tgz b/grafana/charts/feature-auto-instrumentation/charts/beyla-1.7.3.tgz new file mode 100644 index 0000000000000000000000000000000000000000..343a3e23f7a79af1a75d4a33c31ea8219892a17f GIT binary patch literal 10382 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%0AA7IPwmRlSPdE)Fb z9zaZm0OyUMGEX%JyI_iPMo+K_FbN5zk!Zi;952roDGk|#g;*sdf(m#_gDJ#3B(a6b zl%*5qLh`w8O!OcKf^|f;a*3;pW5QyEq#n*#>WP5Uw|m<=yI_hxrA*Ff1`IKp6ItBg z`rp6&kFVyeuYRlt@UwDY@#rwTf}dLso);Ibo(B#(&c5{u*$yX1TplYik!Y#oV5b?8 zVy!x?RTO78iROm(XYn`(%7ky78( zKQKFD=-aQ#G^iYVqI+4~*J}POuL43qc2B4I!^l`&*2sT_N`tPk15;Z%ezSiX-JQ+N zogHn2=pn909$p2By#Apu9E%fW%w@zxfYM$m$?!BkqZD2KSC*%m3Z}ep(p|Qy4x!-l zR9pMSJYP@8wcmW*GS_~1DL~JauO>LVZ7t93M2lC9mB z`E?6fXEwFBTNSx2H-;}C4__vK>qjj$$Nydw39Ink$*O#U88wBYT4cg# z907@AeueWhLobjgLS}>|a5ZD$3~LCu=6O~g+@~W-B%?OaL?hHkHpFCjue?svCgOKL z^SzvkUoy8VP)=)SJ~hGVlKPOb3VYm>%y9T9$6CillrC1jjSZiq8Bb|e_=`49%QH84 z4ScM|mUb<#1K0~gnkttMgD;xs<%zUP!MYfj9yQJm>j=g;?rAgVcQ~=p3yjC~%(xRk zk~{di?z#WXHh!K_v>(*C(`8Ox?d?0pj3U%48efwVSo=}&9ZtFqiDbOAm~=Z)9dglP z2k-00f>nKovhOBpsRf;`f~U=>I;zQbDt)2wZQBslWI0X=H3QsYS_YV@QAjmhjWvQn zay(;Duck5~880@^m>dtrlK>7r4#A&End(s~!_=?fR&La6VrD~E>Z4P|CIYrZ2Co_e zhZHuxBD0NBx!@Mfmc;YKbN?B!^&fT{)*iRyw2 z%wDWk(8V5&rqbS1--u)(iQ{X1W)qOwj-4k0_KpvgY>sFm8HvSzwKdae7@X>OFcpQQ zCk?dA8yc)mZ)suK95&_Jrm_Xmv7CkGv@>Gs=;`=3t_+#`CeST0U1q{8YZ0)wQcP(= zGwg?6&{05bpuadh*+tN#XV&AGwajiEXlsdXqH^_z+PZ5CBHC0_y}T-wSsMF8e``nh zx3@jtW`+7g-|rO@d0D;N(nBuS>iDFVhi_J~Gm_dh>~g-oJv%!ta=%;X(addcbr0IT zgBlvvE^KXP6=Tf;suXU*>df-3^0rRRmWG-(fu*8_8NeAzMJ;31n8buSvszg=al-MX z8@lz}_#*+lQJpIYZeI65P})XMkgp@7S+VCz}1Ri>Faxkd@k st~if=9~8w0X7r1Jski=D&J2Bg9-qhO-~IW&0RRC1|J{**i2&LF0K2C_%>V!Z literal 0 HcmV?d00001 diff --git a/grafana/charts/feature-auto-instrumentation/schema-mods/remote-beyla-config-data.jq b/grafana/charts/feature-auto-instrumentation/schema-mods/remote-beyla-config-data.jq new file mode 100644 index 0000000..ca8ccb2 --- /dev/null +++ b/grafana/charts/feature-auto-instrumentation/schema-mods/remote-beyla-config-data.jq @@ -0,0 +1 @@ +del(.properties.beyla.properties.config.properties.data.properties) diff --git a/grafana/charts/feature-auto-instrumentation/schema-mods/types-and-enums.json b/grafana/charts/feature-auto-instrumentation/schema-mods/types-and-enums.json new file mode 100644 index 0000000..374770d --- /dev/null +++ b/grafana/charts/feature-auto-instrumentation/schema-mods/types-and-enums.json @@ -0,0 +1,5 @@ +{ + "properties": { + "beyla": {"properties": {"preset": {"enum": ["application", "network"]}}} + } +} diff --git a/grafana/charts/feature-auto-instrumentation/templates/_helpers.tpl b/grafana/charts/feature-auto-instrumentation/templates/_helpers.tpl new file mode 100644 index 0000000..a37170c --- /dev/null +++ b/grafana/charts/feature-auto-instrumentation/templates/_helpers.tpl @@ -0,0 +1,29 @@ +{{/* +Create a default fully qualified 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 "feature.autoInstrumentation.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" | lower }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride | lower }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" | lower }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" | lower }} +{{- end }} +{{- end }} +{{- end }} + +{{- define "escape_annotation" -}} +{{ . | replace "-" "_" | replace "." "_" | replace "/" "_" }} +{{- end }} + +{{- define "pod_annotation" -}} +{{ printf "__meta_kubernetes_pod_annotation_%s" (include "escape_annotation" .) }} +{{- end }} + +{{- define "service_annotation" -}} +{{ printf "__meta_kubernetes_service_annotation_%s" (include "escape_annotation" .) }} +{{- end }} diff --git a/grafana/charts/feature-auto-instrumentation/templates/_module.alloy.tpl b/grafana/charts/feature-auto-instrumentation/templates/_module.alloy.tpl new file mode 100644 index 0000000..d7f165e --- /dev/null +++ b/grafana/charts/feature-auto-instrumentation/templates/_module.alloy.tpl @@ -0,0 +1,89 @@ +{{- define "feature.autoInstrumentation.module" }} +{{- $metricAllowList := .Values.beyla.metricsTuning.includeMetrics }} +{{- $metricDenyList := .Values.beyla.metricsTuning.excludeMetrics }} +{{- $labelSelectors := list }} +{{- range $k, $v := .Values.beyla.labelMatchers }} +{{- $labelSelectors = append $labelSelectors (printf "%s=%s" $k $v) }} +{{- end }} +declare "auto_instrumentation" { + argument "metrics_destinations" { + comment = "Must be a list of metric destinations where collected metrics should be forwarded to" + } + + discovery.kubernetes "beyla_pods" { + role = "pod" + namespaces { + own_namespace = true + } + selectors { + role = "pod" + label = {{ $labelSelectors | join "," | quote }} + } + } + + discovery.relabel "beyla_pods" { + targets = discovery.kubernetes.beyla_pods.targets + rule { + source_labels = ["__meta_kubernetes_pod_node_name"] + action = "replace" + target_label = "instance" + } + +{{- if .Values.beyla.extraDiscoveryRules }} +{{ .Values.beyla.extraDiscoveryRules | indent 4 }} +{{- end }} + } + + prometheus.scrape "beyla_applications" { + targets = discovery.relabel.beyla_pods.output + honor_labels = true + scrape_interval = {{ .Values.beyla.scrapeInterval | default .Values.global.scrapeInterval | quote }} + clustering { + enabled = true + } +{{- if or $metricAllowList $metricDenyList .Values.beyla.extraMetricProcessingRules }} + forward_to = [prometheus.relabel.beyla.receiver] +{{- else }} + forward_to = argument.metrics_destinations.value +{{- end }} + } + + prometheus.scrape "beyla_internal" { + targets = discovery.relabel.beyla_pods.output + metrics_path = "/internal/metrics" + job_name = "integrations/beyla" + honor_labels = true + scrape_interval = {{ .Values.beyla.scrapeInterval | default .Values.global.scrapeInterval | quote }} + clustering { + enabled = true + } +{{- if or $metricAllowList $metricDenyList .Values.beyla.extraMetricProcessingRules }} + forward_to = [prometheus.relabel.beyla.receiver] + } + +prometheus.relabel "beyla" { + max_cache_size = {{ .Values.beyla.maxCacheSize | default .Values.global.maxCacheSize | int }} +{{- if $metricAllowList }} + rule { + source_labels = ["__name__"] + regex = "up|scrape_samples_scraped|{{ $metricAllowList | join "|" }}" + action = "keep" + } +{{- end }} +{{- if $metricDenyList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricDenyList | join "|" | quote }} + action = "drop" + } +{{- end }} +{{- if .Values.beyla.extraMetricProcessingRules }} +{{ .Values.beyla.extraMetricProcessingRules | indent 4 }} +{{- end }} +{{- end }} + forward_to = argument.metrics_destinations.value + } +} +{{- end -}} + +{{- define "feature.autoInstrumentation.alloyModules" }}{{- end }} diff --git a/grafana/charts/feature-auto-instrumentation/templates/_notes.tpl b/grafana/charts/feature-auto-instrumentation/templates/_notes.tpl new file mode 100644 index 0000000..84e3800 --- /dev/null +++ b/grafana/charts/feature-auto-instrumentation/templates/_notes.tpl @@ -0,0 +1,13 @@ +{{- define "feature.autoInstrumentation.notes.deployments" }} +* Grafana Beyla (Daemonset) +{{- end }} + +{{- define "feature.autoInstrumentation.notes.task" }} +Automatically instrument applications and services running in the cluster with Grafana Beyla +{{- end }} + +{{- define "feature.autoInstrumentation.notes.actions" }}{{- end }} + +{{- define "feature.autoInstrumentation.summary" -}} +version: {{ .Chart.Version }} +{{- end }} diff --git a/grafana/charts/feature-auto-instrumentation/templates/configmap.yaml b/grafana/charts/feature-auto-instrumentation/templates/configmap.yaml new file mode 100644 index 0000000..23e8781 --- /dev/null +++ b/grafana/charts/feature-auto-instrumentation/templates/configmap.yaml @@ -0,0 +1,11 @@ +{{- if .Values.deployAsConfigMap }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "feature.autoInstrumentation.fullname" . }} + namespace: {{ .Release.Namespace }} +data: + module.alloy: |- + {{- include "feature.autoInstrumentation.module" . | indent 4 }} +{{- end }} diff --git a/grafana/charts/feature-auto-instrumentation/templates/platform_specific/openshift/beyla-scc.yaml b/grafana/charts/feature-auto-instrumentation/templates/platform_specific/openshift/beyla-scc.yaml new file mode 100644 index 0000000..575b023 --- /dev/null +++ b/grafana/charts/feature-auto-instrumentation/templates/platform_specific/openshift/beyla-scc.yaml @@ -0,0 +1,66 @@ +{{- if eq .Values.global.platform "openshift" }} +--- +apiVersion: security.openshift.io/v1 +kind: SecurityContextConstraints +metadata: + name: {{ include "beyla.fullname" .Subcharts.beyla }} +allowHostDirVolumePlugin: true +allowHostIPC: false +allowHostNetwork: true +allowHostPID: true +allowHostPorts: false +allowPrivilegeEscalation: true +allowPrivilegedContainer: true +allowedCapabilities: [] +defaultAddCapabilities: null +defaultAllowPrivilegeEscalation: false +forbiddenSysctls: + - '*' +fsGroup: + type: RunAsAny +groups: [] +priority: null +readOnlyRootFilesystem: false +requiredDropCapabilities: null +runAsUser: + type: RunAsAny +seLinuxContext: + type: RunAsAny +seccompProfiles: + - runtime/default +supplementalGroups: + type: RunAsAny +users: + - system:serviceaccount:{{ .Release.Namespace }}:{{ include "beyla.fullname" .Subcharts.beyla }} +volumes: + - configMap + - hostPath + - projected +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "beyla.fullname" .Subcharts.beyla }}-scc +rules: + - verbs: + - use + apiGroups: + - security.openshift.io + resources: + - securitycontextconstraints + resourceNames: + - {{ include "beyla.fullname" .Subcharts.beyla }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "beyla.fullname" .Subcharts.beyla }}-scc +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "beyla.fullname" .Subcharts.beyla }}-scc +subjects: + - kind: ServiceAccount + name: {{ include "beyla.fullname" .Subcharts.beyla }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/grafana/charts/feature-auto-instrumentation/tests/__snapshot__/.gitkeep b/grafana/charts/feature-auto-instrumentation/tests/__snapshot__/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/grafana/charts/feature-auto-instrumentation/tests/default_test.yaml b/grafana/charts/feature-auto-instrumentation/tests/default_test.yaml new file mode 100644 index 0000000..e094c05 --- /dev/null +++ b/grafana/charts/feature-auto-instrumentation/tests/default_test.yaml @@ -0,0 +1,61 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test default values +templates: + - configmap.yaml +tests: + - it: creates a module with default Beyla configuration + set: + deployAsConfigMap: true + asserts: + - isKind: + of: ConfigMap + - equal: + path: data["module.alloy"] + value: |- + declare "auto_instrumentation" { + argument "metrics_destinations" { + comment = "Must be a list of metric destinations where collected metrics should be forwarded to" + } + + discovery.kubernetes "beyla_pods" { + role = "pod" + namespaces { + own_namespace = true + } + selectors { + role = "pod" + label = "app.kubernetes.io/name=beyla" + } + } + + discovery.relabel "beyla_pods" { + targets = discovery.kubernetes.beyla_pods.targets + rule { + source_labels = ["__meta_kubernetes_pod_node_name"] + action = "replace" + target_label = "instance" + } + } + + prometheus.scrape "beyla_applications" { + targets = discovery.relabel.beyla_pods.output + honor_labels = true + scrape_interval = "60s" + clustering { + enabled = true + } + forward_to = argument.metrics_destinations.value + } + + prometheus.scrape "beyla_internal" { + targets = discovery.relabel.beyla_pods.output + metrics_path = "/internal/metrics" + job_name = "integrations/beyla" + honor_labels = true + scrape_interval = "60s" + clustering { + enabled = true + } + forward_to = argument.metrics_destinations.value + } + } diff --git a/grafana/charts/feature-auto-instrumentation/values.schema.json b/grafana/charts/feature-auto-instrumentation/values.schema.json new file mode 100644 index 0000000..d59cd09 --- /dev/null +++ b/grafana/charts/feature-auto-instrumentation/values.schema.json @@ -0,0 +1,113 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "beyla": { + "type": "object", + "properties": { + "config": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "data": { + "type": "object" + }, + "skipConfigMapCheck": { + "type": "boolean" + } + } + }, + "extraDiscoveryRules": { + "type": "string" + }, + "extraMetricProcessingRules": { + "type": "string" + }, + "labelMatchers": { + "type": "object", + "properties": { + "app.kubernetes.io/name": { + "type": "string" + } + } + }, + "maxCacheSize": { + "type": "null" + }, + "metricsTuning": { + "type": "object", + "properties": { + "excludeMetrics": { + "type": "array" + }, + "includeMetrics": { + "type": "array" + } + } + }, + "nodeSelector": { + "type": "object", + "properties": { + "kubernetes.io/os": { + "type": "string" + } + } + }, + "podAnnotations": { + "type": "object", + "properties": { + "k8s.grafana.com/job": { + "type": "string" + }, + "k8s.grafana.com/logs.job": { + "type": "string" + } + } + }, + "preset": { + "type": "string", + "enum": [ + "application", + "network" + ] + }, + "scrapeInterval": { + "type": "string" + }, + "service": { + "type": "object", + "properties": { + "targetPort": { + "type": "integer" + } + } + } + } + }, + "deployAsConfigMap": { + "type": "boolean" + }, + "fullnameOverride": { + "type": "string" + }, + "global": { + "type": "object", + "properties": { + "maxCacheSize": { + "type": "integer" + }, + "platform": { + "type": "string" + }, + "scrapeInterval": { + "type": "string" + } + } + }, + "nameOverride": { + "type": "string" + } + } +} diff --git a/grafana/charts/feature-auto-instrumentation/values.yaml b/grafana/charts/feature-auto-instrumentation/values.yaml new file mode 100644 index 0000000..7cf152f --- /dev/null +++ b/grafana/charts/feature-auto-instrumentation/values.yaml @@ -0,0 +1,122 @@ +# yamllint disable rule:comments-indentation +--- +# -- Name override +# @section -- General settings +nameOverride: "" + +# -- Full name override +# @section -- General settings +fullnameOverride: "" + +global: + # -- The specific platform for this cluster. Will enable compatibility for some platforms. Supported options: (empty) or "openshift". + # @section -- Global Settings + platform: "" + + # -- How frequently to scrape metrics. + # @section -- Global Settings + scrapeInterval: 60s + + # -- Sets the max_cache_size for every prometheus.relabel component. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus.relabel/#arguments)) + # This should be at least 2x-5x your largest scrape target or samples appended rate. + # @section -- Global Settings + maxCacheSize: 100000 + +beyla: + # -- The configuration preset to use. Valid options are "application" or "network". + # @section -- Beyla + preset: application + + # -- How frequently to scrape metrics from Beyla. + # Overrides metrics.scrapeInterval + # @default -- 60s + # @section -- Beyla + scrapeInterval: "" + + # -- Label matchers used to select the Beyla pods for scraping metrics. + # @section -- Beyla + labelMatchers: + app.kubernetes.io/name: beyla + + # -- Rule blocks to be added to the discovery.relabel component for Beyla. + # These relabeling rules are applied pre-scrape against the targets from service discovery. + # Before the scrape, any remaining target labels that start with __ (i.e. __meta_kubernetes*) are dropped. + # ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery.relabel/#rule-block)) + # @section -- Beyla + extraDiscoveryRules: "" + + # -- Rule blocks to be added to the prometheus.relabel component for Beyla. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus.relabel/#rule-block)) + # These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no __meta* labels are present. + # @section -- Beyla + extraMetricProcessingRules: "" + + # Adjustments to the scraped metrics to filter the amount of data sent to storage. + # @section -- Beyla + metricsTuning: + # -- Metrics to keep. Can use regular expressions. + # @section -- Beyla + includeMetrics: [] + # -- Metrics to drop. Can use regular expressions. + # @section -- Beyla + excludeMetrics: [] + + # -- Sets the max_cache_size for the prometheus.relabel component for Beyla. + # This should be at least 2x-5x your largest scrape target or samples appended rate. + # ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus.relabel/#arguments)) + # Overrides metrics.maxCacheSize + # @default -- 100000 + # @section -- Beyla + maxCacheSize: + + config: + # @ignored -- This allows this chart to create the ConfigMap while also keeping the default name + skipConfigMapCheck: true + # @ignored -- This allows this chart to create the Beyla ConfigMap with required modifications + create: false + + # -- The configuration for Grafana Beyla + # Some sections will be set automatically, such as the cluster name. + # Others will be modified depending on the value of beyla.preset. + # @section -- Beyla + data: + attributes: + kubernetes: + enable: true + # @ignored -- This will be replaced by the actual cluster name + # cluster_name: "" + internal_metrics: + prometheus: + # @ignored -- This will be replaced with service.targetPort below + port: 9090 + path: /internal/metrics + prometheus_export: + # @ignored -- This will be replaced with service.targetPort below + port: 9090 + path: /metrics + features: + - application + - network + - application_service_graph + - application_span + + # @ignored -- If the Application Observability feature is enabled, and if there is an HTTP or gRPC receiver, the + # endpoint will be set here. + # otel_traces_export: + # endpoint: "" + + # -- The port number for the Beyla service. + # @section -- Beyla + service: + targetPort: 9090 + + # @ignored + podAnnotations: + k8s.grafana.com/job: default/beyla + k8s.grafana.com/logs.job: integrations/beyla + + # @ignored -- Beyla can only install to Linux nodes + nodeSelector: + kubernetes.io/os: linux + +# @ignore +deployAsConfigMap: false diff --git a/grafana/charts/feature-cluster-events/.helmignore b/grafana/charts/feature-cluster-events/.helmignore new file mode 100644 index 0000000..2b29eaf --- /dev/null +++ b/grafana/charts/feature-cluster-events/.helmignore @@ -0,0 +1,6 @@ +docs +schema-mods +tests +Makefile +README.md +README.md.gotmpl diff --git a/grafana/charts/feature-cluster-events/Chart.lock b/grafana/charts/feature-cluster-events/Chart.lock new file mode 100644 index 0000000..1e36a52 --- /dev/null +++ b/grafana/charts/feature-cluster-events/Chart.lock @@ -0,0 +1,3 @@ +dependencies: [] +digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726 +generated: "2024-08-21T14:40:45.012164-05:00" diff --git a/grafana/charts/feature-cluster-events/Chart.yaml b/grafana/charts/feature-cluster-events/Chart.yaml new file mode 100644 index 0000000..3651861 --- /dev/null +++ b/grafana/charts/feature-cluster-events/Chart.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: v2 +name: feature-cluster-events +description: Gathers Kubernetes Events +icon: https://raw.githubusercontent.com/grafana/grafana/main/public/img/grafana_icon.svg +sources: + - https://github.com/grafana/k8s-monitoring-helm/tree/main/charts/k8s-monitoring/charts/feature-cluster-events +version: 1.0.0 +appVersion: 1.0.0 +maintainers: + - email: pete.wall@grafana.com + name: petewall +dependencies: [] diff --git a/grafana/charts/feature-cluster-events/Makefile b/grafana/charts/feature-cluster-events/Makefile new file mode 100644 index 0000000..107caf8 --- /dev/null +++ b/grafana/charts/feature-cluster-events/Makefile @@ -0,0 +1,34 @@ +HAS_HELM_DOCS := $(shell command -v helm-docs;) +HAS_HELM_UNITTEST := $(shell helm plugin list | grep unittest 2> /dev/null) + +.SECONDEXPANSION: +README.md: values.yaml Chart.yaml $$(wildcard README.md.gotmpl) +ifdef HAS_HELM_DOCS + helm-docs +else + docker run --rm --volume "$(shell pwd):/helm-docs" -u $(shell id -u) jnorwood/helm-docs:latest +endif + +Chart.lock: Chart.yaml + helm dependency update . + @touch Chart.lock # Ensure the timestamp is updated + +values.schema.json: values.yaml $$(wildcard schema-mods/*) + ../../../../scripts/schema-gen.sh . + +.PHONY: clean +clean: + rm -f README.md values.schema.json + +.PHONY: build +build: README.md Chart.lock values.schema.json + +.PHONY: test +test: build + helm lint . + ct lint --lint-conf ../../../../.configs/lintconf.yaml --helm-dependency-extra-args=--skip-refresh --charts . +ifdef HAS_HELM_UNITTEST + helm unittest . +else + docker run --rm --volume $(shell pwd):/apps helmunittest/helm-unittest:3.17.0-0.7.1 . +endif diff --git a/grafana/charts/feature-cluster-events/README.md b/grafana/charts/feature-cluster-events/README.md new file mode 100644 index 0000000..3300d85 --- /dev/null +++ b/grafana/charts/feature-cluster-events/README.md @@ -0,0 +1,65 @@ + + +# feature-cluster-events + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) +Gathers Kubernetes Events + +The Cluster Events feature enables the collection of Kubernetes events from the cluster. + +## How it works + +Events are captured as logs and are annotated with additional metadata to make them easier to search and filter. + +## Testing + +This chart contains unit tests to verify the generated configuration. The hidden value `deployAsConfigMap` will render +the generated configuration into a ConfigMap object. While this ConfigMap is not used during regular operation, you can +use it to show the outcome of a given values file. + +The unit tests use this ConfigMap to create an object with the configuration that can be asserted against. To run the +tests, use `helm test`. + +Be sure perform actual integration testing in a live environment in the main [k8s-monitoring](../..) chart. + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| petewall | | | + + +## Source Code + +* + + + +## Values + +### Gather settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| excludeNamespaces | list | `[]` | List of namespaces to ignore events for. | +| logFormat | string | `"logfmt"` | Log format used to forward cluster events. Allowed values: `logfmt` (default), `json`. | +| namespaces | list | `[]` | List of namespaces to watch for events (`[]` means all namespaces) | + +### Processing settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| extraLogProcessingStages | string | `""` | Stage blocks to be added to the loki.process component for cluster events. ([docs](https://grafana.com/docs/alloy/latest/reference/components/loki/loki.process/#blocks)) This value is templated so that you can refer to other values from this file. | +| jobLabel | string | `"integrations/kubernetes/eventhandler"` | The value for the job label. | +| labelsToKeep | list | `["job","level","namespace","node","source"]` | The list of labels to keep on the logs, all other pipeline labels will be dropped. | +| structuredMetadata | object | `{}` | The structured metadata mappings to set. To not set any structured metadata, set this to an empty object (e.g. `{}`) Format: `: `. Example: structuredMetadata: component: component kind: kind name: name | + +### General settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| fullnameOverride | string | `""` | Full name override | +| nameOverride | string | `""` | Name override | diff --git a/grafana/charts/feature-cluster-events/README.md.gotmpl b/grafana/charts/feature-cluster-events/README.md.gotmpl new file mode 100644 index 0000000..b82b6ff --- /dev/null +++ b/grafana/charts/feature-cluster-events/README.md.gotmpl @@ -0,0 +1,36 @@ + + +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} +{{ template "chart.badgesSection" . }} +{{ template "chart.description" . }} +{{ template "chart.homepageLine" . }} + +The Cluster Events feature enables the collection of Kubernetes events from the cluster. + +## How it works + +Events are captured as logs and are annotated with additional metadata to make them easier to search and filter. + +## Testing + +This chart contains unit tests to verify the generated configuration. The hidden value `deployAsConfigMap` will render +the generated configuration into a ConfigMap object. While this ConfigMap is not used during regular operation, you can +use it to show the outcome of a given values file. + +The unit tests use this ConfigMap to create an object with the configuration that can be asserted against. To run the +tests, use `helm test`. + +Be sure perform actual integration testing in a live environment in the main [k8s-monitoring](../..) chart. + +{{ template "chart.maintainersSection" . }} + + +{{ template "chart.sourcesSection" . }} + + +{{ template "chart.requirementsSection" . }} +{{ template "chart.valuesSection" . }} diff --git a/grafana/charts/feature-cluster-events/templates/_helpers.tpl b/grafana/charts/feature-cluster-events/templates/_helpers.tpl new file mode 100644 index 0000000..a282412 --- /dev/null +++ b/grafana/charts/feature-cluster-events/templates/_helpers.tpl @@ -0,0 +1,17 @@ +{{/* +Create a default fully qualified 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 "feature.clusterEvents.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" | lower }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride | lower }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" | lower }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" | lower }} +{{- end }} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-cluster-events/templates/_module.alloy.tpl b/grafana/charts/feature-cluster-events/templates/_module.alloy.tpl new file mode 100644 index 0000000..2fcc1d0 --- /dev/null +++ b/grafana/charts/feature-cluster-events/templates/_module.alloy.tpl @@ -0,0 +1,120 @@ +{{- define "feature.clusterEvents.module" }} +declare "cluster_events" { + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + loki.source.kubernetes_events "cluster_events" { + job_name = {{ .Values.jobLabel | quote }} + log_format = "{{ .Values.logFormat }}" + {{- if .Values.namespaces }} + namespaces = {{ .Values.namespaces | toJson }} + {{- end }} + forward_to = [loki.process.cluster_events.receiver] + } + + loki.process "cluster_events" { + {{- if .Values.excludeNamespaces }} + stage.drop { + source = "namespace" + expression = {{ .Values.excludeNamespaces | join "|" | quote }} + drop_counter_reason = "excluded_namespaces" + } + {{- end }} + + // add a static source label to the logs so they can be differentiated / restricted if necessary + stage.static_labels { + values = { + "source" = "kubernetes-events", + } + } + + // extract some of the fields from the log line, these could be used as labels, structured metadata, etc. + {{- if eq .Values.logFormat "json" }} + stage.json { + expressions = { + "component" = "sourcecomponent", // map the sourcecomponent field to component + "kind" = "", + "level" = "type", // most events don't have a level but they do have a "type" i.e. Normal, Warning, Error, etc. + "name" = "", + "node" = "sourcehost", // map the sourcehost field to node + } + } + {{- else }} + stage.logfmt { + mapping = { + "component" = "sourcecomponent", // map the sourcecomponent field to component + "kind" = "", + "level" = "type", // most events don't have a level but they do have a "type" i.e. Normal, Warning, Error, etc. + "name" = "", + "node" = "sourcehost", // map the sourcehost field to node + } + } + {{- end }} + // set these values as labels, they may or may not be used as index labels in Loki as they can be dropped + // prior to being written to Loki, but this makes them available + stage.labels { + values = { + "component" = "", + "kind" = "", + "level" = "", + "name" = "", + "node" = "", + } + } + + // if kind=Node, set the node label by copying the instance label + stage.match { + selector = "{kind=\"Node\"}" + + stage.labels { + values = { + "node" = "name", + } + } + } + + // set the level extracted key value as a normalized log level + stage.match { + selector = "{level=\"Normal\"}" + + stage.static_labels { + values = { + level = "Info", + } + } + } + + {{- if .Values.extraLogProcessingStages }} + {{ tpl .Values.extraLogProcessingStages $ | indent 4 }} + {{ end }} + + {{- /* the stage.structured_metadata block needs to be conditionalized because the support for enabling structured metadata can be disabled */ -}} + {{- /* through the loki limits_conifg on a per-tenant basis, even if there are no values defined or there are values defined but it is disabled */ -}} + {{- /* in Loki, the write will fail. */ -}} + {{- if gt (len (keys .Values.structuredMetadata)) 0 }} + // set the structured metadata values + stage.structured_metadata { + values = { + {{- range $key, $value := .Values.structuredMetadata }} + {{ $key | quote }} = {{ if $value }}{{ $value | quote }}{{ else }}{{ $key | quote }}{{ end }}, + {{- end }} + } + } + {{- end }} + + // Only keep the labels that are defined in the `keepLabels` list. + stage.label_keep { + values = {{ .Values.labelsToKeep | toJson }} + } + stage.labels { + values = { + "service_name" = "job", + } + } + forward_to = argument.logs_destinations.value + } +} +{{- end -}} + +{{- define "feature.clusterEvents.alloyModules" }}{{- end }} diff --git a/grafana/charts/feature-cluster-events/templates/_notes.tpl b/grafana/charts/feature-cluster-events/templates/_notes.tpl new file mode 100644 index 0000000..b5aa085 --- /dev/null +++ b/grafana/charts/feature-cluster-events/templates/_notes.tpl @@ -0,0 +1,11 @@ +{{- define "feature.clusterEvents.notes.deployments" }}{{- end }} + +{{- define "feature.clusterEvents.notes.task" }} +Gather Kubernetes Cluster events{{- if .Values.namespaces }} from the namespaces {{ .Values.namespaces | join "," }}{{- end }} +{{- end }} + +{{- define "feature.clusterEvents.notes.actions" }}{{- end }} + +{{- define "feature.clusterEvents.summary" -}} +version: {{ .Chart.Version }} +{{- end }} diff --git a/grafana/charts/feature-cluster-events/templates/configmap.yaml b/grafana/charts/feature-cluster-events/templates/configmap.yaml new file mode 100644 index 0000000..ed9f9b7 --- /dev/null +++ b/grafana/charts/feature-cluster-events/templates/configmap.yaml @@ -0,0 +1,13 @@ +{{- if .Values.deployAsConfigMap }} +{{- $alloyConfig := include "feature.clusterEvents.module" . }} +{{- $alloyConfig = regexReplaceAll `[ \t]+(\r?\n)` $alloyConfig "\n" }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "feature.clusterEvents.fullname" . }} + namespace: {{ .Release.Namespace }} +data: + module.alloy: |- + {{- $alloyConfig | trim | nindent 4 }} +{{- end }} diff --git a/grafana/charts/feature-cluster-events/tests/__snapshot__/default_test.yaml.snap b/grafana/charts/feature-cluster-events/tests/__snapshot__/default_test.yaml.snap new file mode 100644 index 0000000..c5dd707 --- /dev/null +++ b/grafana/charts/feature-cluster-events/tests/__snapshot__/default_test.yaml.snap @@ -0,0 +1,79 @@ +should create a ConfigMap: + 1: | + |- + declare "cluster_events" { + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + loki.source.kubernetes_events "cluster_events" { + job_name = "integrations/kubernetes/eventhandler" + log_format = "logfmt" + forward_to = [loki.process.cluster_events.receiver] + } + + loki.process "cluster_events" { + + // add a static source label to the logs so they can be differentiated / restricted if necessary + stage.static_labels { + values = { + "source" = "kubernetes-events", + } + } + + // extract some of the fields from the log line, these could be used as labels, structured metadata, etc. + stage.logfmt { + mapping = { + "component" = "sourcecomponent", // map the sourcecomponent field to component + "kind" = "", + "level" = "type", // most events don't have a level but they do have a "type" i.e. Normal, Warning, Error, etc. + "name" = "", + "node" = "sourcehost", // map the sourcehost field to node + } + } + // set these values as labels, they may or may not be used as index labels in Loki as they can be dropped + // prior to being written to Loki, but this makes them available + stage.labels { + values = { + "component" = "", + "kind" = "", + "level" = "", + "name" = "", + "node" = "", + } + } + + // if kind=Node, set the node label by copying the instance label + stage.match { + selector = "{kind=\"Node\"}" + + stage.labels { + values = { + "node" = "name", + } + } + } + + // set the level extracted key value as a normalized log level + stage.match { + selector = "{level=\"Normal\"}" + + stage.static_labels { + values = { + level = "Info", + } + } + } + + // Only keep the labels that are defined in the `keepLabels` list. + stage.label_keep { + values = ["job","level","namespace","node","source"] + } + stage.labels { + values = { + "service_name" = "job", + } + } + forward_to = argument.logs_destinations.value + } + } diff --git a/grafana/charts/feature-cluster-events/tests/__snapshot__/extra_processing_stages_test.yaml.snap b/grafana/charts/feature-cluster-events/tests/__snapshot__/extra_processing_stages_test.yaml.snap new file mode 100644 index 0000000..45ca491 --- /dev/null +++ b/grafana/charts/feature-cluster-events/tests/__snapshot__/extra_processing_stages_test.yaml.snap @@ -0,0 +1,84 @@ +should create a ConfigMap with extra processing stages: + 1: | + |- + declare "cluster_events" { + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + loki.source.kubernetes_events "cluster_events" { + job_name = "integrations/kubernetes/eventhandler" + log_format = "logfmt" + forward_to = [loki.process.cluster_events.receiver] + } + + loki.process "cluster_events" { + + // add a static source label to the logs so they can be differentiated / restricted if necessary + stage.static_labels { + values = { + "source" = "kubernetes-events", + } + } + + // extract some of the fields from the log line, these could be used as labels, structured metadata, etc. + stage.logfmt { + mapping = { + "component" = "sourcecomponent", // map the sourcecomponent field to component + "kind" = "", + "level" = "type", // most events don't have a level but they do have a "type" i.e. Normal, Warning, Error, etc. + "name" = "", + "node" = "sourcehost", // map the sourcehost field to node + } + } + // set these values as labels, they may or may not be used as index labels in Loki as they can be dropped + // prior to being written to Loki, but this makes them available + stage.labels { + values = { + "component" = "", + "kind" = "", + "level" = "", + "name" = "", + "node" = "", + } + } + + // if kind=Node, set the node label by copying the instance label + stage.match { + selector = "{kind=\"Node\"}" + + stage.labels { + values = { + "node" = "name", + } + } + } + + // set the level extracted key value as a normalized log level + stage.match { + selector = "{level=\"Normal\"}" + + stage.static_labels { + values = { + level = "Info", + } + } + } + stage.drop { + source = "namespace" + value = "private" + } + + + // Only keep the labels that are defined in the `keepLabels` list. + stage.label_keep { + values = ["job","level","namespace","node","source"] + } + stage.labels { + values = { + "service_name" = "job", + } + } + forward_to = argument.logs_destinations.value + } + } diff --git a/grafana/charts/feature-cluster-events/tests/__snapshot__/labels_test.yaml.snap b/grafana/charts/feature-cluster-events/tests/__snapshot__/labels_test.yaml.snap new file mode 100644 index 0000000..c95ba6d --- /dev/null +++ b/grafana/charts/feature-cluster-events/tests/__snapshot__/labels_test.yaml.snap @@ -0,0 +1,79 @@ +should create a ConfigMap that sets custom labels to keep: + 1: | + |- + declare "cluster_events" { + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + loki.source.kubernetes_events "cluster_events" { + job_name = "integrations/kubernetes/eventhandler" + log_format = "logfmt" + forward_to = [loki.process.cluster_events.receiver] + } + + loki.process "cluster_events" { + + // add a static source label to the logs so they can be differentiated / restricted if necessary + stage.static_labels { + values = { + "source" = "kubernetes-events", + } + } + + // extract some of the fields from the log line, these could be used as labels, structured metadata, etc. + stage.logfmt { + mapping = { + "component" = "sourcecomponent", // map the sourcecomponent field to component + "kind" = "", + "level" = "type", // most events don't have a level but they do have a "type" i.e. Normal, Warning, Error, etc. + "name" = "", + "node" = "sourcehost", // map the sourcehost field to node + } + } + // set these values as labels, they may or may not be used as index labels in Loki as they can be dropped + // prior to being written to Loki, but this makes them available + stage.labels { + values = { + "component" = "", + "kind" = "", + "level" = "", + "name" = "", + "node" = "", + } + } + + // if kind=Node, set the node label by copying the instance label + stage.match { + selector = "{kind=\"Node\"}" + + stage.labels { + values = { + "node" = "name", + } + } + } + + // set the level extracted key value as a normalized log level + stage.match { + selector = "{level=\"Normal\"}" + + stage.static_labels { + values = { + level = "Info", + } + } + } + + // Only keep the labels that are defined in the `keepLabels` list. + stage.label_keep { + values = ["job","namespace","level","node","name","source"] + } + stage.labels { + values = { + "service_name" = "job", + } + } + forward_to = argument.logs_destinations.value + } + } diff --git a/grafana/charts/feature-cluster-events/tests/__snapshot__/namespace_test.yaml.snap b/grafana/charts/feature-cluster-events/tests/__snapshot__/namespace_test.yaml.snap new file mode 100644 index 0000000..84d32e2 --- /dev/null +++ b/grafana/charts/feature-cluster-events/tests/__snapshot__/namespace_test.yaml.snap @@ -0,0 +1,80 @@ +should create a ConfigMap that restricts events to the given namespaces: + 1: | + |- + declare "cluster_events" { + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + loki.source.kubernetes_events "cluster_events" { + job_name = "integrations/kubernetes/eventhandler" + log_format = "logfmt" + namespaces = ["a","b"] + forward_to = [loki.process.cluster_events.receiver] + } + + loki.process "cluster_events" { + + // add a static source label to the logs so they can be differentiated / restricted if necessary + stage.static_labels { + values = { + "source" = "kubernetes-events", + } + } + + // extract some of the fields from the log line, these could be used as labels, structured metadata, etc. + stage.logfmt { + mapping = { + "component" = "sourcecomponent", // map the sourcecomponent field to component + "kind" = "", + "level" = "type", // most events don't have a level but they do have a "type" i.e. Normal, Warning, Error, etc. + "name" = "", + "node" = "sourcehost", // map the sourcehost field to node + } + } + // set these values as labels, they may or may not be used as index labels in Loki as they can be dropped + // prior to being written to Loki, but this makes them available + stage.labels { + values = { + "component" = "", + "kind" = "", + "level" = "", + "name" = "", + "node" = "", + } + } + + // if kind=Node, set the node label by copying the instance label + stage.match { + selector = "{kind=\"Node\"}" + + stage.labels { + values = { + "node" = "name", + } + } + } + + // set the level extracted key value as a normalized log level + stage.match { + selector = "{level=\"Normal\"}" + + stage.static_labels { + values = { + level = "Info", + } + } + } + + // Only keep the labels that are defined in the `keepLabels` list. + stage.label_keep { + values = ["job","level","namespace","node","source"] + } + stage.labels { + values = { + "service_name" = "job", + } + } + forward_to = argument.logs_destinations.value + } + } diff --git a/grafana/charts/feature-cluster-events/tests/__snapshot__/structured_metadata_test.yaml.snap b/grafana/charts/feature-cluster-events/tests/__snapshot__/structured_metadata_test.yaml.snap new file mode 100644 index 0000000..b077a51 --- /dev/null +++ b/grafana/charts/feature-cluster-events/tests/__snapshot__/structured_metadata_test.yaml.snap @@ -0,0 +1,87 @@ +should create a ConfigMap that sets structured metadata k/v pairs: + 1: | + |- + declare "cluster_events" { + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + loki.source.kubernetes_events "cluster_events" { + job_name = "integrations/kubernetes/eventhandler" + log_format = "logfmt" + forward_to = [loki.process.cluster_events.receiver] + } + + loki.process "cluster_events" { + + // add a static source label to the logs so they can be differentiated / restricted if necessary + stage.static_labels { + values = { + "source" = "kubernetes-events", + } + } + + // extract some of the fields from the log line, these could be used as labels, structured metadata, etc. + stage.logfmt { + mapping = { + "component" = "sourcecomponent", // map the sourcecomponent field to component + "kind" = "", + "level" = "type", // most events don't have a level but they do have a "type" i.e. Normal, Warning, Error, etc. + "name" = "", + "node" = "sourcehost", // map the sourcehost field to node + } + } + // set these values as labels, they may or may not be used as index labels in Loki as they can be dropped + // prior to being written to Loki, but this makes them available + stage.labels { + values = { + "component" = "", + "kind" = "", + "level" = "", + "name" = "", + "node" = "", + } + } + + // if kind=Node, set the node label by copying the instance label + stage.match { + selector = "{kind=\"Node\"}" + + stage.labels { + values = { + "node" = "name", + } + } + } + + // set the level extracted key value as a normalized log level + stage.match { + selector = "{level=\"Normal\"}" + + stage.static_labels { + values = { + level = "Info", + } + } + } + // set the structured metadata values + stage.structured_metadata { + values = { + "component" = "component", + "kind" = "kind", + "name" = "name", + } + } + + // Only keep the labels that are defined in the `keepLabels` list. + stage.label_keep { + values = ["job","level","namespace","node","source"] + } + stage.labels { + values = { + "service_name" = "job", + } + } + forward_to = argument.logs_destinations.value + } + } diff --git a/grafana/charts/feature-cluster-events/tests/default_test.yaml b/grafana/charts/feature-cluster-events/tests/default_test.yaml new file mode 100644 index 0000000..2235773 --- /dev/null +++ b/grafana/charts/feature-cluster-events/tests/default_test.yaml @@ -0,0 +1,13 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test default values +templates: + - configmap.yaml +tests: + - it: should create a ConfigMap + set: + deployAsConfigMap: true + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] diff --git a/grafana/charts/feature-cluster-events/tests/extra_processing_stages_test.yaml b/grafana/charts/feature-cluster-events/tests/extra_processing_stages_test.yaml new file mode 100644 index 0000000..334a056 --- /dev/null +++ b/grafana/charts/feature-cluster-events/tests/extra_processing_stages_test.yaml @@ -0,0 +1,18 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test extra processing stages +templates: + - configmap.yaml +tests: + - it: should create a ConfigMap with extra processing stages + set: + deployAsConfigMap: true + extraLogProcessingStages: |- + stage.drop { + source = "namespace" + value = "private" + } + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] diff --git a/grafana/charts/feature-cluster-events/tests/labels_test.yaml b/grafana/charts/feature-cluster-events/tests/labels_test.yaml new file mode 100644 index 0000000..7c69175 --- /dev/null +++ b/grafana/charts/feature-cluster-events/tests/labels_test.yaml @@ -0,0 +1,20 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test namespaces +templates: + - configmap.yaml +tests: + - it: should create a ConfigMap that sets custom labels to keep + set: + deployAsConfigMap: true + labelsToKeep: + - job + - namespace + - level + - node + - name + - source + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] diff --git a/grafana/charts/feature-cluster-events/tests/namespace_test.yaml b/grafana/charts/feature-cluster-events/tests/namespace_test.yaml new file mode 100644 index 0000000..f6f6832 --- /dev/null +++ b/grafana/charts/feature-cluster-events/tests/namespace_test.yaml @@ -0,0 +1,14 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test namespaces +templates: + - configmap.yaml +tests: + - it: should create a ConfigMap that restricts events to the given namespaces + set: + deployAsConfigMap: true + namespaces: ["a", "b"] + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] diff --git a/grafana/charts/feature-cluster-events/tests/structured_metadata_test.yaml b/grafana/charts/feature-cluster-events/tests/structured_metadata_test.yaml new file mode 100644 index 0000000..38c0a09 --- /dev/null +++ b/grafana/charts/feature-cluster-events/tests/structured_metadata_test.yaml @@ -0,0 +1,17 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test namespaces +templates: + - configmap.yaml +tests: + - it: should create a ConfigMap that sets structured metadata k/v pairs + set: + deployAsConfigMap: true + structuredMetadata: + kind: kind + component: component + name: name + asserts: + - isKind: + of: ConfigMap + - matchSnapshot: + path: data["module.alloy"] diff --git a/grafana/charts/feature-cluster-events/values.schema.json b/grafana/charts/feature-cluster-events/values.schema.json new file mode 100644 index 0000000..b895482 --- /dev/null +++ b/grafana/charts/feature-cluster-events/values.schema.json @@ -0,0 +1,39 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "deployAsConfigMap": { + "type": "boolean" + }, + "excludeNamespaces": { + "type": "array" + }, + "extraLogProcessingStages": { + "type": "string" + }, + "fullnameOverride": { + "type": "string" + }, + "jobLabel": { + "type": "string" + }, + "labelsToKeep": { + "type": "array", + "items": { + "type": "string" + } + }, + "logFormat": { + "type": "string" + }, + "nameOverride": { + "type": "string" + }, + "namespaces": { + "type": "array" + }, + "structuredMetadata": { + "type": "object" + } + } +} diff --git a/grafana/charts/feature-cluster-events/values.yaml b/grafana/charts/feature-cluster-events/values.yaml new file mode 100644 index 0000000..bdf3c45 --- /dev/null +++ b/grafana/charts/feature-cluster-events/values.yaml @@ -0,0 +1,53 @@ +--- +# -- Name override +# @section -- General settings +nameOverride: "" + +# -- Full name override +# @section -- General settings +fullnameOverride: "" + +# -- List of namespaces to watch for events (`[]` means all namespaces) +# @section -- Gather settings +namespaces: [] + +# -- List of namespaces to ignore events for. +# @section -- Gather settings +excludeNamespaces: [] + +# -- Log format used to forward cluster events. Allowed values: `logfmt` (default), `json`. +# @section -- Gather settings +logFormat: logfmt + +# -- The value for the job label. +# @section -- Processing settings +jobLabel: "integrations/kubernetes/eventhandler" + +# -- Stage blocks to be added to the loki.process component for cluster events. +# ([docs](https://grafana.com/docs/alloy/latest/reference/components/loki/loki.process/#blocks)) +# This value is templated so that you can refer to other values from this file. +# @section -- Processing settings +extraLogProcessingStages: "" + +# -- The list of labels to keep on the logs, all other pipeline labels will be dropped. +# @section -- Processing settings +labelsToKeep: + - job + - level + - namespace + - node + - source + +# -- The structured metadata mappings to set. +# To not set any structured metadata, set this to an empty object (e.g. `{}`) +# Format: `: `. +# Example: +# structuredMetadata: +# component: component +# kind: kind +# name: name +# @section -- Processing settings +structuredMetadata: {} + +# @ignore +deployAsConfigMap: false diff --git a/grafana/charts/feature-cluster-metrics/.ct.yaml b/grafana/charts/feature-cluster-metrics/.ct.yaml new file mode 100644 index 0000000..7a53888 --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/.ct.yaml @@ -0,0 +1,4 @@ +--- +chart-repos: + - kepler=https://sustainable-computing-io.github.io/kepler-helm-chart + - prometheus-community=https://prometheus-community.github.io/helm-charts diff --git a/grafana/charts/feature-cluster-metrics/.helmignore b/grafana/charts/feature-cluster-metrics/.helmignore new file mode 100644 index 0000000..2b29eaf --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/.helmignore @@ -0,0 +1,6 @@ +docs +schema-mods +tests +Makefile +README.md +README.md.gotmpl diff --git a/grafana/charts/feature-cluster-metrics/Chart.lock b/grafana/charts/feature-cluster-metrics/Chart.lock new file mode 100644 index 0000000..38e4ee0 --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/Chart.lock @@ -0,0 +1,18 @@ +dependencies: +- name: kube-state-metrics + repository: https://prometheus-community.github.io/helm-charts + version: 5.32.0 +- name: prometheus-node-exporter + repository: https://prometheus-community.github.io/helm-charts + version: 4.45.2 +- name: prometheus-windows-exporter + repository: https://prometheus-community.github.io/helm-charts + version: 0.10.0 +- name: kepler + repository: https://sustainable-computing-io.github.io/kepler-helm-chart + version: 0.5.13 +- name: opencost + repository: https://opencost.github.io/opencost-helm-chart + version: 1.43.2 +digest: sha256:19e851fee0b7e51df9b948648a5d1ab6b92abd241dc3fecc30199fcaf2438e6a +generated: "2025-04-21T16:34:51.131211-05:00" diff --git a/grafana/charts/feature-cluster-metrics/Chart.yaml b/grafana/charts/feature-cluster-metrics/Chart.yaml new file mode 100644 index 0000000..dd0b5dd --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/Chart.yaml @@ -0,0 +1,39 @@ +--- +apiVersion: v2 +name: feature-cluster-metrics +description: Gathers Kubernetes Cluster metrics +icon: https://raw.githubusercontent.com/grafana/grafana/main/public/img/grafana_icon.svg +sources: + - https://github.com/grafana/k8s-monitoring-helm/tree/main/charts/k8s-monitoring/charts/feature-cluster-metrics +version: 1.0.0 +appVersion: 1.0.0 +maintainers: + - email: pete.wall@grafana.com + name: petewall +dependencies: + - name: kube-state-metrics + version: 5.32.0 + repository: https://prometheus-community.github.io/helm-charts + condition: kube-state-metrics.deploy + + - alias: node-exporter + name: prometheus-node-exporter + version: 4.45.2 + repository: https://prometheus-community.github.io/helm-charts + condition: node-exporter.deploy + + - alias: windows-exporter + name: prometheus-windows-exporter + version: 0.10.0 + repository: https://prometheus-community.github.io/helm-charts + condition: windows-exporter.deploy + + - name: kepler + version: 0.5.13 + repository: https://sustainable-computing-io.github.io/kepler-helm-chart + condition: kepler.enabled + + - name: opencost + version: 1.43.2 + repository: https://opencost.github.io/opencost-helm-chart + condition: opencost.enabled diff --git a/grafana/charts/feature-cluster-metrics/Makefile b/grafana/charts/feature-cluster-metrics/Makefile new file mode 100644 index 0000000..1296b41 --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/Makefile @@ -0,0 +1,42 @@ +HAS_HELM_DOCS := $(shell command -v helm-docs;) +HAS_HELM_UNITTEST := $(shell helm plugin list | grep unittest 2> /dev/null) +ALLOW_LISTS := default-allow-lists/kube-state-metrics.yaml + +.SECONDEXPANSION: +README.md: values.yaml Chart.yaml $$(wildcard README.md.gotmpl) +ifdef HAS_HELM_DOCS + helm-docs +else + docker run --rm --volume "$(shell pwd):/helm-docs" -u $(shell id -u) jnorwood/helm-docs:latest +endif + +Chart.lock: Chart.yaml + helm dependency update . + @touch Chart.lock # Ensure the timestamp is updated + +values.schema.json: values.yaml $$(wildcard schema-mods/*) + ../../../../scripts/schema-gen.sh . + +default-allow-lists/%.yaml: ../../../../allowLists/%.yaml + cp $< $@ + +.PHONY: clean +clean: + rm -f README.md values.schema.json $(ALLOW_LISTS) + +.PHONY: build +build: README.md Chart.lock values.schema.json $(ALLOW_LISTS) + +.PHONY: test +test: build + helm repo add prometheus-community https://prometheus-community.github.io/helm-charts + helm repo add kepler https://sustainable-computing-io.github.io/kepler-helm-chart + helm repo add opencost https://opencost.github.io/opencost-helm-chart + + helm lint . + ct lint --lint-conf ../../../../.configs/lintconf.yaml --helm-dependency-extra-args=--skip-refresh --charts . +ifdef HAS_HELM_UNITTEST + helm unittest . +else + docker run --rm --volume $(shell pwd):/apps helmunittest/helm-unittest:3.17.0-0.7.1 . +endif diff --git a/grafana/charts/feature-cluster-metrics/README.md b/grafana/charts/feature-cluster-metrics/README.md new file mode 100644 index 0000000..91b789d --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/README.md @@ -0,0 +1,385 @@ + + +# feature-cluster-metrics + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) + +Gathers Kubernetes Cluster metrics + +This chart deploys the Cluster Metrics feature of the Kubernetes Observability Helm chart, which uses allow +lists to limit the metrics needed. An allow list is a set of metric names that will be kept, while any metrics +not on the list will be dropped. With [metrics tuning](#metrics-tuning--allow-lists), you can further customize which metrics are collected. + +## How it works + +This chart includes the ability to collect metrics from the following: + +* The Kubernetes cluster itself +* Sources like the Kubelet and cAdvisor +* Common supporting services like [kube-state-metrics](https://github.com/kubernetes/kube-state-metrics) and + [Node Exporter](https://github.com/prometheus/node_exporter) +* Systems to capture additional data like Kepler + +### Metrics sources + +The Cluster Metrics feature of the Kubernetes Observability Helm chart includes the following metric systems and +their default allow lists: + +| Metric source | Gathers information about | Allow list | +|------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| API Server | Kubernetes API Server | NA | +| [cAdvisor](https://github.com/google/cadvisor) | Containers on each node | [default-allow-lists/cadvisor.yaml](./default-allow-lists/cadvisor.yaml) | +| [Kepler](https://sustainable-computing.io/) | Kubernetes cluster | [default-allow-lists/kepler.yaml](./default-allow-lists/kepler.yaml) | +| Kube Controller Manager | Kubernetes Controller Manager | NA | +| Kube Proxy | Kube Proxy | NA | +| Kube Scheduler | Kube Scheduler | NA | +| Kubelet | Kubernetes information on each node | [default-allow-lists/kubelet.yaml](./default-allow-lists/kubelet.yaml) | +| [kube-state-metrics](https://github.com/kubernetes/kube-state-metrics) | Kubernetes | | +| resources inside the cluster | [default-allow-lists/kube-state-metrics.yaml](./default-allow-lists/kube-state-metrics.yaml) | | +| [Node Exporter](https://github.com/prometheus/node_exporter) | Linux Kubernetes nodes | [default-allow-lists/node-exporter.yaml](./default-allow-lists/node-exporter.yaml), [default-allow-lists/node-exporter-integration.yaml](./default-allow-lists/node-exporter-integration.yaml) | +| [Windows Exporter](https://github.com/prometheus-community/windows_exporter) | Windows Kubernetes nodes | [default-allow-lists/windows-exporter.yaml](./default-allow-lists/windows-exporter.yaml) | + +## Metrics tuning and allow lists + +For any metric source, you can adjust the amount of metrics being scraped and their labels to limit the number of metrics delivered to your destinations. Many of the metric sources have a default allow list. The allow list for a metric source is designed to return a useful, but minimal set of metrics for typical use cases. Some metrics sources have an integration allow list, which contains even more metrics for diving into the details of the source itself. + +To control metrics with allow lists or label filters, use the `metricsTuning` section in the values file. + +```yaml +: + metricsTuning: + useDefaultAllowList: # Use the allow list for this metric source + useIntegrationAllowList: # Use the integration allow list for this metric source + includeMetrics: [] # Metrics to be kept + excludeMetrics: [] # Metrics to be dropped +``` + +The behavior of the combination of these settings is shown in this table: + +| Allow list | includeMetrics | excludeMetrics | Result | +|------------|------------------|--------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| +| true | `[]` | `[]` | Use the allow list metric list | +| false | `[]` | `[]` | No filter, keep all metrics | +| true | `[my_metric]` | `[]` | Use the allow list metric list with an additional metric | +| false | `[my_metric_.*]` | `[]` | *Only* keep metrics that start with `my_metric_` | +| true | `[]` | `[my_metric_.*]` | Use the allow list metric filter, but exclude anything that starts with `my_metric_` | +| false | `[]` | `[my_metric_.*]` | Keep all metrics except anything that starts with `my_metric_` | +| true | `[my_metric_.*]` | `[other_metric_.*]` | Use the allow list metric filter, and keep anything that starts with `my_metric_`, but remove anything that starts with `other_metric_` | +| false | `[my_metric_.*]` | `[my_metric_not_needed]` | *Only* keep metrics that start with `my_metric_`, but remove any that are named `my_metric_not_needed` | + +## Relabeling rules + +You can also use relabeling rules to take any action on the metrics allow list, such as to filter based on a label. +To do so, use `extraMetricProcessingRules` section in the values file to add arbitrary relabeling rules. + +## Testing + +This chart contains unit tests to verify the generated configuration. The hidden value `deployAsConfigMap` will render +the generated configuration into a ConfigMap object. While this ConfigMap is not used during regular operation, you can +use it to show the outcome of a given values file. + +The unit tests use this ConfigMap to create an object with the configuration that can be asserted against. To run the +tests, use `helm test`. + +Be sure perform actual integration testing in a live environment in the main [k8s-monitoring](../..) chart. + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| petewall | | | + + + +## Source Code + +* + + +## Requirements + +| Repository | Name | Version | +|------------|------|---------| +| https://opencost.github.io/opencost-helm-chart | opencost | 1.43.2 | +| https://prometheus-community.github.io/helm-charts | kube-state-metrics | 5.32.0 | +| https://prometheus-community.github.io/helm-charts | node-exporter(prometheus-node-exporter) | 4.45.2 | +| https://prometheus-community.github.io/helm-charts | windows-exporter(prometheus-windows-exporter) | 0.10.0 | +| https://sustainable-computing-io.github.io/kepler-helm-chart | kepler | 0.5.13 | + + + +## Values + +### API Server + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| apiServer.enabled | bool | `false` | Scrape metrics from the API Server. | +| apiServer.extraDiscoveryRules | string | `""` | Rule blocks to be added to the discovery.relabel component for the API Server. These relabeling rules are applied pre-scrape against the targets from service discovery. Before the scrape, any remaining target labels that start with `__` (i.e. `__meta_kubernetes*`) are dropped. ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) | +| apiServer.extraMetricProcessingRules | string | `""` | Rule blocks to be added to the prometheus.relabel component for the API Server. These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no `__meta*` labels are present. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#rule-block)) | +| apiServer.jobLabel | string | `"integrations/kubernetes/kube-apiserver"` | The value for the job label. | +| apiServer.maxCacheSize | string | `nil` | Sets the max_cache_size for the API Server prometheus.relabel component. This should be at least 2x-5x your largest scrape target or samples appended rate. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) Overrides metrics.maxCacheSize | +| apiServer.metricsTuning.excludeMetrics | list | `[]` | Metrics to drop. Can use regular expressions. | +| apiServer.metricsTuning.includeMetrics | list | `[]` | Metrics to keep. Can use regular expressions. An empty list means keep all. | +| apiServer.scrapeInterval | string | 60s | How frequently to scrape metrics from the API Server Overrides metrics.scrapeInterval | + +### cAdvisor + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| cadvisor.enabled | bool | `true` | Scrape metrics from cAdvisor. | +| cadvisor.extraDiscoveryRules | string | `""` | Rule blocks to be added to the discovery.relabel component for cAdvisor. These relabeling rules are applied pre-scrape against the targets from service discovery. Before the scrape, any remaining target labels that start with `__` (i.e. `__meta_kubernetes*`) are dropped. ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) | +| cadvisor.extraMetricProcessingRules | string | `""` | Rule blocks to be added to the prometheus.relabel component for cAdvisor metrics. These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no `__meta*` labels are present. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#rule-block)) | +| cadvisor.jobLabel | string | `"integrations/kubernetes/cadvisor"` | The value for the job label. | +| cadvisor.maxCacheSize | string | `100000` | Sets the max_cache_size for the cAdvisor prometheus.relabel component. This should be at least 2x-5x your largest scrape target or samples appended rate. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) Overrides global.maxCacheSize | +| cadvisor.metricsTuning.dropEmptyContainerLabels | bool | `true` | Drop metrics that have an empty container label | +| cadvisor.metricsTuning.dropEmptyImageLabels | bool | `true` | Drop metrics that have an empty image label | +| cadvisor.metricsTuning.excludeMetrics | list | `[]` | Metrics to drop. Can use regular expressions. | +| cadvisor.metricsTuning.excludeNamespaces | list | `[]` | For metrics with a `namespace` label, drop those that are in this list. | +| cadvisor.metricsTuning.includeMetrics | list | `[]` | Metrics to keep. Can use regular expressions. | +| cadvisor.metricsTuning.includeNamespaces | list | `[]` | For metrics with a `namespace` label, only keep those that are in this list. | +| cadvisor.metricsTuning.keepPhysicalFilesystemDevices | list | `["mmcblk.p.+","nvme.+","rbd.+","sd.+","vd.+","xvd.+","dasd.+"]` | Only keep filesystem metrics that use the following physical devices | +| cadvisor.metricsTuning.keepPhysicalNetworkDevices | list | `["en[ospx][0-9].*","wlan[0-9].*","eth[0-9].*"]` | Only keep network metrics that use the following physical devices | +| cadvisor.metricsTuning.normalizeUnnecessaryLabels | list | `[{"labels":["boot_id","system_uuid"],"metric":"machine_memory_bytes"}]` | Normalize labels to the same value for the given metric and label pairs | +| cadvisor.metricsTuning.useDefaultAllowList | bool | `true` | Filter the list of metrics from cAdvisor to the minimal set required for Kubernetes Monitoring. | +| cadvisor.nodeAddressFormat | string | `"direct"` | How to access cAdvisor to get metrics, either "direct" (use node IP) or "proxy" (uses API Server) | + +### cadvisor + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| cadvisor.scrapeInterval | string | `60s` | How frequently to scrape cAdvisor metrics. | + +### Control Plane + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| controlPlane.enabled | bool | `false` | enable all Kubernetes Control Plane metrics sources. This includes api-server, kube-scheduler, kube-controller-manager, and KubeDNS. | + +### General settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| fullnameOverride | string | `""` | Full name override | +| nameOverride | string | `""` | Name override | + +### Global Settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| global.alloyModules.branch | string | `"main"` | If using git, the branch of the git repository to use. | +| global.alloyModules.source | string | `"git"` | The source of the Alloy modules. The valid options are "configMap" or "git" | +| global.kubernetesAPIService | string | `""` | The Kubernetes service. Change this if your cluster DNS is configured differently than the default. | +| global.maxCacheSize | int | `100000` | Sets the max_cache_size for every prometheus.relabel component. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) This should be at least 2x-5x your largest scrape target or samples appended rate. | +| global.platform | string | `""` | The specific platform for this cluster. Will enable compatibility for some platforms. Supported options: (empty) or "openshift". | +| global.scrapeInterval | string | `"60s"` | How frequently to scrape metrics. | + +### Kepler + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| kepler.enabled | bool | `false` | Deploy and scrape Kepler metrics. | +| kepler.extraDiscoveryRules | string | `""` | Rule blocks to be added to the discovery.relabel component for Kepler. These relabeling rules are applied pre-scrape against the targets from service discovery. Before the scrape, any remaining target labels that start with __ (i.e. __meta_kubernetes*) are dropped. ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) | +| kepler.extraMetricProcessingRules | string | `""` | Rule blocks to be added to the prometheus.relabel component for Kepler. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#rule-block)) These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no __meta* labels are present. | +| kepler.jobLabel | string | `"integrations/kepler"` | The value for the job label. | +| kepler.labelMatchers | object | `{"app.kubernetes.io/name":"kepler"}` | Label matchers used to select the Kepler pods | +| kepler.maxCacheSize | string | `100000` | Sets the max_cache_size for the prometheus.relabel component for Kepler. This should be at least 2x-5x your largest scrape target or samples appended rate. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) Overrides global.maxCacheSize | +| kepler.metricsTuning.excludeMetrics | list | `[]` | Metrics to drop. Can use regular expressions. | +| kepler.metricsTuning.includeMetrics | list | `[]` | Metrics to keep. Can use regular expressions. | +| kepler.metricsTuning.useDefaultAllowList | bool | `true` | Filter the list of metrics from Kepler to the minimal set required for Kubernetes Monitoring. | +| kepler.scrapeInterval | string | `60s` | How frequently to scrape metrics from Kepler. Overrides global.scrapeInterval. | + +### kube-state-metrics + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| kube-state-metrics.bearerTokenFile | string | `""` | The bearer token file to use when scraping metrics from kube-state-metrics. | +| kube-state-metrics.deploy | bool | `true` | Deploy kube-state-metrics. Set to false if your cluster already has kube-state-metrics deployed. | +| kube-state-metrics.discoveryType | string | `"endpoints"` | How to discover the kube-state-metrics service. Either `endpoints` or `pod`. | +| kube-state-metrics.enabled | bool | `true` | Scrape metrics from kube-state-metrics. | +| kube-state-metrics.extraDiscoveryRules | string | `""` | Rule blocks to be added to the discovery.relabel component for kube-state-metrics. These relabeling rules are applied pre-scrape against the targets from service discovery. Before the scrape, any remaining target labels that start with __ (i.e. __meta_kubernetes*) are dropped. ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) | +| kube-state-metrics.extraMetricProcessingRules | string | `""` | Rule blocks to be added to the prometheus.relabel component for kube-state-metrics metrics. These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no `__meta*` labels are present. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#rule-block)) | +| kube-state-metrics.jobLabel | string | `"integrations/kubernetes/kube-state-metrics"` | The value for the job label. | +| kube-state-metrics.labelMatchers | object | `{"app.kubernetes.io/name":"kube-state-metrics"}` | Labels used to select the kube-state-metrics service. | +| kube-state-metrics.maxCacheSize | string | `100000` | Sets the max_cache_size for the kube-state-metrics prometheus.relabel component. This should be at least 2x-5x your largest scrape target or samples appended rate. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) Overrides global.maxCacheSize | +| kube-state-metrics.metricLabelsAllowlist | list | `["nodes=[agentpool,alpha.eksctl.io/cluster-name,alpha.eksctl.io/nodegroup-name,beta.kubernetes.io/instance-type,cloud.google.com/gke-nodepool,cluster-name,ec2.amazonaws.com/Name,ec2.amazonaws.com/aws-autoscaling-groupName,ec2.amazonaws.com/aws-autoscaling-group-name,ec2.amazonaws.com/name,eks.amazonaws.com/nodegroup,k8s.io/cloud-provider-aws,karpenter.sh/nodepool,kubernetes.azure.com/cluster,kubernetes.io/arch,kubernetes.io/hostname,kubernetes.io/os,node.kubernetes.io/instance-type,topology.kubernetes.io/region,topology.kubernetes.io/zone]"]` | `kube__labels` metrics to generate. The default is to include a useful set for Node labels. | +| kube-state-metrics.metricsTuning.excludeMetrics | list | `[]` | Metrics to drop. Can use regular expressions. | +| kube-state-metrics.metricsTuning.includeMetrics | list | `[]` | Metrics to keep. Can use regular expressions. | +| kube-state-metrics.metricsTuning.useDefaultAllowList | bool | `true` | Filter the list of metrics from Kube State Metrics to a useful, minimal set. | +| kube-state-metrics.namespace | string | `""` | Namespace to locate kube-state-metrics pods. If `deploy` is set to `true`, this will automatically be set to the namespace where this Helm chart is deployed. | +| kube-state-metrics.namespaces | list | `[]` | List (or comma-separated string) of namespaces to be enabled for collecting resources. By default, all namespaces are collected. Requires kube-state-metrics to be deployed by this chart. | +| kube-state-metrics.namespacesDenylist | list | `[]` | List (or comma-separated string) of namespaces to be excluded from collecting resources. If namespaces and namespaces denylist are both set, only namespaces that are excluded in namespaces denylist will be used. Requires kube-state-metrics to be deployed by this chart. | +| kube-state-metrics.scrapeInterval | string | `60s` | How frequently to scrape kube-state-metrics metrics. | +| kube-state-metrics.service.portName | string | `"http"` | The port name used by kube-state-metrics. | +| kube-state-metrics.service.scheme | string | `"http"` | The scrape scheme used by kube-state-metrics. | + +### Kube Controller Manager + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| kubeControllerManager.enabled | bool | `false` | Scrape metrics from the Kube Controller Manager | +| kubeControllerManager.extraDiscoveryRules | string | `""` | Rule blocks to be added to the discovery.relabel component for the Kube Controller Manager. These relabeling rules are applied pre-scrape against the targets from service discovery. Before the scrape, any remaining target labels that start with `__` (i.e. `__meta_kubernetes*`) are dropped. ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) | +| kubeControllerManager.extraMetricProcessingRules | string | `""` | Rule blocks to be added to the prometheus.relabel component for the Kube Controller Manager. These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no `__meta*` labels are present. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#rule-block)) | +| kubeControllerManager.jobLabel | string | `"kube-controller-manager"` | The value for the job label. | +| kubeControllerManager.maxCacheSize | string | `nil` | Sets the max_cache_size for the Kube Controller Manager prometheus.relabel component. This should be at least 2x-5x your largest scrape target or samples appended rate. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) Overrides metrics.maxCacheSize | +| kubeControllerManager.metricsTuning.excludeMetrics | list | `[]` | Metrics to drop. Can use regular expressions. | +| kubeControllerManager.metricsTuning.includeMetrics | list | `[]` | Metrics to keep. Can use regular expressions. An empty list means keep all. | +| kubeControllerManager.port | int | `10257` | Port number used by the Kube Controller Manager, set by `--secure-port.` | +| kubeControllerManager.scrapeInterval | string | 60s | How frequently to scrape metrics from the Kube Controller Manager Overrides metrics.scrapeInterval | +| kubeControllerManager.selectorLabel | string | `"component=kube-controller-manager"` | Selector label. | + +### KubeDNS + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| kubeDNS.enabled | bool | `false` | Scrape metrics from KubeDNS | +| kubeDNS.extraDiscoveryRules | string | `""` | Rule blocks to be added to the discovery.relabel component for KubeDNS. These relabeling rules are applied pre-scrape against the targets from service discovery. Before the scrape, any remaining target labels that start with `__` (i.e. `__meta_kubernetes*`) are dropped. ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) | +| kubeDNS.extraMetricProcessingRules | string | `""` | Rule blocks to be added to the prometheus.relabel component for KubeDNS. These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no `__meta*` labels are present. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#rule-block)) | +| kubeDNS.jobLabel | string | `"integrations/kubernetes/kube-dns"` | The value for the job label. | +| kubeDNS.maxCacheSize | string | `nil` | Sets the max_cache_size for the KubeDNS prometheus.relabel component. This should be at least 2x-5x your largest scrape target or samples appended rate. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) Overrides metrics.maxCacheSize | +| kubeDNS.metricsTuning.excludeMetrics | list | `[]` | Metrics to drop. Can use regular expressions. | +| kubeDNS.metricsTuning.includeMetrics | list | `[]` | Metrics to keep. Can use regular expressions. An empty list means keep all. | +| kubeDNS.scrapeInterval | string | 60s | How frequently to scrape metrics from KubeDNS Overrides metrics.scrapeInterval | + +### Kube Proxy + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| kubeProxy.enabled | bool | `false` | Scrape metrics from the Kube Proxy | +| kubeProxy.extraDiscoveryRules | string | `""` | Rule blocks to be added to the discovery.relabel component for the Kube Proxy. These relabeling rules are applied pre-scrape against the targets from service discovery. Before the scrape, any remaining target labels that start with `__` (i.e. `__meta_kubernetes*`) are dropped. ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) | +| kubeProxy.extraMetricProcessingRules | string | `""` | Rule blocks to be added to the prometheus.relabel component for the Kube Proxy. These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no `__meta*` labels are present. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#rule-block)) | +| kubeProxy.jobLabel | string | `"integrations/kubernetes/kube-proxy"` | The value for the job label. | +| kubeProxy.maxCacheSize | string | `nil` | Sets the max_cache_size for the Kube Proxy prometheus.relabel component. This should be at least 2x-5x your largest scrape target or samples appended rate. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) Overrides metrics.maxCacheSize | +| kubeProxy.metricsTuning.excludeMetrics | list | `[]` | Metrics to drop. Can use regular expressions. | +| kubeProxy.metricsTuning.includeMetrics | list | `[]` | Metrics to keep. Can use regular expressions. An empty list means keep all. | +| kubeProxy.port | int | `10249` | Port number used by the Kube Proxy, set in `--metrics-bind-address`. | +| kubeProxy.scrapeInterval | string | 60s | How frequently to scrape metrics from the Kube Proxy Overrides metrics.scrapeInterval | +| kubeProxy.selectorLabel | string | `"k8s-app=kube-proxy"` | Selector label. | + +### Kube Scheduler + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| kubeScheduler.enabled | bool | `false` | Scrape metrics from the Kube Scheduler | +| kubeScheduler.extraDiscoveryRules | string | `""` | Rule blocks to be added to the discovery.relabel component for the Kube Scheduler. These relabeling rules are applied pre-scrape against the targets from service discovery. Before the scrape, any remaining target labels that start with `__` (i.e. `__meta_kubernetes*`) are dropped. ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) | +| kubeScheduler.extraMetricProcessingRules | string | `""` | Rule blocks to be added to the prometheus.relabel component for the Kube Scheduler. These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no `__meta*` labels are present. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#rule-block)) | +| kubeScheduler.jobLabel | string | `"kube-scheduler"` | The value for the job label. | +| kubeScheduler.maxCacheSize | string | `nil` | Sets the max_cache_size for the Kube Scheduler prometheus.relabel component. This should be at least 2x-5x your largest scrape target or samples appended rate. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) Overrides metrics.maxCacheSize | +| kubeScheduler.metricsTuning.excludeMetrics | list | `[]` | Metrics to drop. Can use regular expressions. | +| kubeScheduler.metricsTuning.includeMetrics | list | `[]` | Metrics to keep. Can use regular expressions. An empty list means keep all. | +| kubeScheduler.port | int | `10259` | Port number used by the Kube Scheduler, set by `--secure-port`. | +| kubeScheduler.scrapeInterval | string | 60s | How frequently to scrape metrics from the Kube Scheduler Overrides metrics.scrapeInterval | +| kubeScheduler.selectorLabel | string | `"component=kube-scheduler"` | Selector label. | + +### Kubelet + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| kubelet.enabled | bool | `true` | Scrape metrics from kubelet. | +| kubelet.extraDiscoveryRules | string | `""` | Rule blocks to be added to the discovery.relabel component for the Kubelet. These relabeling rules are applied pre-scrape against the targets from service discovery. Before the scrape, any remaining target labels that start with `__` (i.e. `__meta_kubernetes*`) are dropped. ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) | +| kubelet.extraMetricProcessingRules | string | `""` | Rule blocks to be added to the prometheus.relabel component for Kubelet metrics. These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no `__meta*` labels are present. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#rule-block)) | +| kubelet.jobLabel | string | `"integrations/kubernetes/kubelet"` | The value for the job label. | +| kubelet.maxCacheSize | string | `100000` | Sets the max_cache_size for the Kubelet prometheus.relabel component. This should be at least 2x-5x your largest scrape target or samples appended rate. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) Overrides global.maxCacheSize | +| kubelet.metricsTuning.excludeMetrics | list | `[]` | Metrics to drop. Can use regular expressions. | +| kubelet.metricsTuning.includeMetrics | list | `[]` | Metrics to keep. Can use regular expressions. | +| kubelet.metricsTuning.useDefaultAllowList | bool | `true` | Filter the list of metrics from the Kubelet to the minimal set required for Kubernetes Monitoring. | +| kubelet.nodeAddressFormat | string | `"direct"` | How to access the Kubelet to get metrics, either "direct" (use node IP) or "proxy" (uses API Server) | +| kubelet.scrapeInterval | string | `60s` | How frequently to scrape Kubelet metrics. | + +### Kubelet Probes + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| kubeletProbes.enabled | bool | `false` | Scrape probe metrics from the Kubelet. | +| kubeletProbes.extraDiscoveryRules | string | `""` | Rule blocks to be added to the discovery.relabel component for Kubelet probes. These relabeling rules are applied pre-scrape against the targets from service discovery. Before the scrape, any remaining target labels that start with `__` (i.e. `__meta_kubernetes*`) are dropped. ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) | +| kubeletProbes.extraMetricProcessingRules | string | `""` | Rule blocks to be added to the prometheus.relabel component for Kubelet probe metrics. These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no `__meta*` labels are present. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#rule-block)) | +| kubeletProbes.jobLabel | string | `"integrations/kubernetes/probes"` | The value for the job label. | +| kubeletProbes.maxCacheSize | string | `100000` | Sets the max_cache_size for prometheus.relabel components. This should be at least 2x-5x your largest scrape target or samples appended rate. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) Overrides global.maxCacheSize | +| kubeletProbes.metricsTuning.excludeMetrics | list | `[]` | Metrics to drop. Can use regular expressions. | +| kubeletProbes.metricsTuning.includeMetrics | list | `[]` | Metrics to keep. Can use regular expressions. | +| kubeletProbes.metricsTuning.useDefaultAllowList | bool | `true` | Filter the list of probe metrics from the Kubelet to the minimal set required for Kubernetes Monitoring. | +| kubeletProbes.nodeAddressFormat | string | `"direct"` | How to access the Kubelet to get probe metrics, either "direct" (use node IP) or "proxy" (uses API Server) | +| kubeletProbes.scrapeInterval | string | `60s` | How frequently to scrape Kubelet probe metrics. | + +### Kubelet Resources + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| kubeletResource.enabled | bool | `true` | Scrape resource metrics from the Kubelet. | +| kubeletResource.extraDiscoveryRules | string | `""` | Rule blocks to be added to the discovery.relabel component for Kubelet resources. These relabeling rules are applied pre-scrape against the targets from service discovery. Before the scrape, any remaining target labels that start with `__` (i.e. `__meta_kubernetes*`) are dropped. ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) | +| kubeletResource.extraMetricProcessingRules | string | `""` | Rule blocks to be added to the prometheus.relabel component for Kubelet resource metrics. These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no `__meta*` labels are present. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#rule-block)) | +| kubeletResource.jobLabel | string | `"integrations/kubernetes/resources"` | The value for the job label. | +| kubeletResource.maxCacheSize | string | `100000` | Sets the max_cache_size for prometheus.relabel components. This should be at least 2x-5x your largest scrape target or samples appended rate. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) Overrides global.maxCacheSize | +| kubeletResource.metricsTuning.excludeMetrics | list | `[]` | Metrics to drop. Can use regular expressions. | +| kubeletResource.metricsTuning.includeMetrics | list | `[]` | Metrics to keep. Can use regular expressions. | +| kubeletResource.metricsTuning.useDefaultAllowList | bool | `true` | Filter the list of resource metrics from the Kubelet to the minimal set required for Kubernetes Monitoring. | +| kubeletResource.nodeAddressFormat | string | `"direct"` | How to access the Kubelet to get resource metrics, either "direct" (use node IP) or "proxy" (uses API Server) | +| kubeletResource.scrapeInterval | string | `60s` | How frequently to scrape Kubelet resource metrics. | + +### Node Exporter + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| node-exporter.bearerTokenFile | string | `""` | The bearer token file to use when scraping metrics from Node Exporter. | +| node-exporter.deploy | bool | `true` | Deploy Node Exporter. Set to false if your cluster already has Node Exporter deployed. | +| node-exporter.enabled | bool | `true` | Scrape metrics from Node Exporter. | +| node-exporter.extraDiscoveryRules | string | `""` | Rule blocks to be added to the discovery.relabel component for Node Exporter. These relabeling rules are applied pre-scrape against the targets from service discovery. Before the scrape, any remaining target labels that start with __ (i.e. __meta_kubernetes*) are dropped. ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) | +| node-exporter.extraMetricProcessingRules | string | `""` | Rule blocks to be added to the prometheus.relabel component for Node Exporter metrics. These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no `__meta*` labels are present. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#rule-block)) | +| node-exporter.jobLabel | string | `"integrations/node_exporter"` | The value for the job label. | +| node-exporter.labelMatchers | object | `{"app.kubernetes.io/name":"node-exporter"}` | Labels used to select the Node Exporter pods. | +| node-exporter.maxCacheSize | string | `100000` | Sets the max_cache_size for the Node Exporter prometheus.relabel component. This should be at least 2x-5x your largest scrape target or samples appended rate. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) Overrides global.maxCacheSize | +| node-exporter.metricsTuning.dropMetricsForFilesystem | list | `["ramfs","tmpfs"]` | Drop metrics for the given filesystem types | +| node-exporter.metricsTuning.excludeMetrics | list | `[]` | Metrics to drop. Can use regular expressions. | +| node-exporter.metricsTuning.includeMetrics | list | `[]` | Metrics to keep. Can use regular expressions. | +| node-exporter.metricsTuning.useDefaultAllowList | bool | `true` | Filter the list of metrics from Node Exporter to the minimal set required for Kubernetes Monitoring. | +| node-exporter.metricsTuning.useIntegrationAllowList | bool | `false` | Filter the list of metrics from Node Exporter to the minimal set required for Kubernetes Monitoring as well as the Node Exporter integration. | +| node-exporter.namespace | string | `""` | Namespace to locate Node Exporter pods. If `deploy` is set to `true`, this will automatically be set to the namespace where this Helm chart is deployed. | +| node-exporter.scrapeInterval | string | `60s` | How frequently to scrape Node Exporter metrics. | +| node-exporter.service.portName | string | `"metrics"` | The port name used by Node Exporter. | +| node-exporter.service.scheme | string | `"http"` | The scrape scheme used by Node Exporter. | + +### OpenCost + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| opencost.enabled | bool | `false` | Deploy and scrape OpenCost. | +| opencost.extraDiscoveryRules | string | `""` | Rule blocks to be added to the discovery.relabel component for OpenCost. These relabeling rules are applied pre-scrape against the targets from service discovery. Before the scrape, any remaining target labels that start with __ (i.e. __meta_kubernetes*) are dropped. ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) | +| opencost.extraMetricProcessingRules | string | `""` | Rule blocks to be added to the prometheus.relabel component for OpenCost. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#rule-block)) These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no __meta* labels are present. | +| opencost.jobLabel | string | `"integrations/opencost"` | The value for the job label. | +| opencost.labelMatchers | object | `{"app.kubernetes.io/name":"opencost"}` | Label matchers used to select the OpenCost service | +| opencost.maxCacheSize | string | `100000` | Sets the max_cache_size for the prometheus.relabel component for OpenCost. This should be at least 2x-5x your largest scrape target or samples appended rate. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) Overrides global.maxCacheSize | +| opencost.metricsSource | string | `""` | The name of the metric destination where OpenCost will query for required metrics. Setting this will enable guided setup for required OpenCost parameters. To skip guided setup, set this to "custom". | +| opencost.metricsTuning.excludeMetrics | list | `[]` | Metrics to drop. Can use regular expressions. | +| opencost.metricsTuning.includeMetrics | list | `[]` | Metrics to keep. Can use regular expressions. | +| opencost.metricsTuning.useDefaultAllowList | bool | `true` | Filter the list of metrics from OpenCost to the minimal set required for Kubernetes Monitoring. | +| opencost.opencost.prometheus.existingSecretName | string | `""` | The name of the secret containing the username and password for the metrics service. This must be in the same namespace as the OpenCost deployment. | +| opencost.opencost.prometheus.external.url | string | `""` | The URL for Prometheus queries. It should match externalServices.prometheus.host + "/api/prom" | +| opencost.opencost.prometheus.password_key | string | `"password"` | The key for the password property in the secret. | +| opencost.opencost.prometheus.username_key | string | `"username"` | The key for the username property in the secret. | +| opencost.scrapeInterval | string | `60s` | How frequently to scrape metrics from Kepler. Overrides global.scrapeInterval. | + +### Windows Exporter - Deployment settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| windows-exporter.deploy | bool | `true` | Deploy Windows Exporter. Set to false if your cluster already has Windows Exporter deployed. | + +### Windows Exporter + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| windows-exporter.enabled | bool | `true` | Scrape node metrics | +| windows-exporter.extraDiscoveryRules | string | `""` | Rule blocks to be added to the discovery.relabel component for Windows Exporter. These relabeling rules are applied pre-scrape against the targets from service discovery. Before the scrape, any remaining target labels that start with __ (i.e. __meta_kubernetes*) are dropped. ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) | +| windows-exporter.extraMetricProcessingRules | string | `""` | Rule blocks to be added to the prometheus.relabel component for Windows Exporter metrics. These relabeling rules are applied post-scrape against the metrics returned from the scraped target, no `__meta*` labels are present. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#rule-block)) | +| windows-exporter.jobLabel | string | `"integrations/windows-exporter"` | The value for the job label. | +| windows-exporter.labelMatchers | object | `{"app.kubernetes.io/name":"windows-exporter"}` | Labels used to select the Windows Exporter pods. | +| windows-exporter.maxCacheSize | string | `100000` | Sets the max_cache_size for the Windows Exporter prometheus.relabel component. This should be at least 2x-5x your largest scrape target or samples appended rate. ([docs](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.relabel/#arguments)) Overrides global.maxCacheSize | +| windows-exporter.metricsTuning.excludeMetrics | list | `[]` | Metrics to drop. Can use regular expressions. | +| windows-exporter.metricsTuning.includeMetrics | list | `[]` | Metrics to keep. Can use regular expressions. | +| windows-exporter.metricsTuning.useDefaultAllowList | bool | `true` | Filter the list of metrics from Windows Exporter to the minimal set required for Kubernetes Monitoring. | +| windows-exporter.namespace | string | `""` | Namespace to locate Windows Exporter pods. If `deploy` is set to `true`, this will automatically be set to the namespace where this Helm chart is deployed. | +| windows-exporter.scrapeInterval | string | `60s` | How frequently to scrape metrics from Windows Exporter. | + diff --git a/grafana/charts/feature-cluster-metrics/README.md.gotmpl b/grafana/charts/feature-cluster-metrics/README.md.gotmpl new file mode 100644 index 0000000..a226118 --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/README.md.gotmpl @@ -0,0 +1,104 @@ + + +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.badgesSection" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +This chart deploys the Cluster Metrics feature of the Kubernetes Observability Helm chart, which uses allow +lists to limit the metrics needed. An allow list is a set of metric names that will be kept, while any metrics +not on the list will be dropped. With [metrics tuning](#metrics-tuning--allow-lists), you can further customize which metrics are collected. + +## How it works + +This chart includes the ability to collect metrics from the following: + +* The Kubernetes cluster itself +* Sources like the Kubelet and cAdvisor +* Common supporting services like [kube-state-metrics](https://github.com/kubernetes/kube-state-metrics) and + [Node Exporter](https://github.com/prometheus/node_exporter) +* Systems to capture additional data like Kepler + +### Metrics sources + +The Cluster Metrics feature of the Kubernetes Observability Helm chart includes the following metric systems and +their default allow lists: + +| Metric source | Gathers information about | Allow list | +|------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| API Server | Kubernetes API Server | NA | +| [cAdvisor](https://github.com/google/cadvisor) | Containers on each node | [default-allow-lists/cadvisor.yaml](./default-allow-lists/cadvisor.yaml) | +| [Kepler](https://sustainable-computing.io/) | Kubernetes cluster | [default-allow-lists/kepler.yaml](./default-allow-lists/kepler.yaml) | +| Kube Controller Manager | Kubernetes Controller Manager | NA | +| Kube Proxy | Kube Proxy | NA | +| Kube Scheduler | Kube Scheduler | NA | +| Kubelet | Kubernetes information on each node | [default-allow-lists/kubelet.yaml](./default-allow-lists/kubelet.yaml) | +| [kube-state-metrics](https://github.com/kubernetes/kube-state-metrics) | Kubernetes | | +| resources inside the cluster | [default-allow-lists/kube-state-metrics.yaml](./default-allow-lists/kube-state-metrics.yaml) | | +| [Node Exporter](https://github.com/prometheus/node_exporter) | Linux Kubernetes nodes | [default-allow-lists/node-exporter.yaml](./default-allow-lists/node-exporter.yaml), [default-allow-lists/node-exporter-integration.yaml](./default-allow-lists/node-exporter-integration.yaml) | +| [Windows Exporter](https://github.com/prometheus-community/windows_exporter) | Windows Kubernetes nodes | [default-allow-lists/windows-exporter.yaml](./default-allow-lists/windows-exporter.yaml) | + +## Metrics tuning and allow lists + +For any metric source, you can adjust the amount of metrics being scraped and their labels to limit the number of metrics delivered to your destinations. Many of the metric sources have a default allow list. The allow list for a metric source is designed to return a useful, but minimal set of metrics for typical use cases. Some metrics sources have an integration allow list, which contains even more metrics for diving into the details of the source itself. + +To control metrics with allow lists or label filters, use the `metricsTuning` section in the values file. + +```yaml +: + metricsTuning: + useDefaultAllowList: # Use the allow list for this metric source + useIntegrationAllowList: # Use the integration allow list for this metric source + includeMetrics: [] # Metrics to be kept + excludeMetrics: [] # Metrics to be dropped +``` + +The behavior of the combination of these settings is shown in this table: + +| Allow list | includeMetrics | excludeMetrics | Result | +|------------|------------------|--------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| +| true | `[]` | `[]` | Use the allow list metric list | +| false | `[]` | `[]` | No filter, keep all metrics | +| true | `[my_metric]` | `[]` | Use the allow list metric list with an additional metric | +| false | `[my_metric_.*]` | `[]` | *Only* keep metrics that start with `my_metric_` | +| true | `[]` | `[my_metric_.*]` | Use the allow list metric filter, but exclude anything that starts with `my_metric_` | +| false | `[]` | `[my_metric_.*]` | Keep all metrics except anything that starts with `my_metric_` | +| true | `[my_metric_.*]` | `[other_metric_.*]` | Use the allow list metric filter, and keep anything that starts with `my_metric_`, but remove anything that starts with `other_metric_` | +| false | `[my_metric_.*]` | `[my_metric_not_needed]` | *Only* keep metrics that start with `my_metric_`, but remove any that are named `my_metric_not_needed` | + +## Relabeling rules + +You can also use relabeling rules to take any action on the metrics allow list, such as to filter based on a label. +To do so, use `extraMetricProcessingRules` section in the values file to add arbitrary relabeling rules. + +## Testing + +This chart contains unit tests to verify the generated configuration. The hidden value `deployAsConfigMap` will render +the generated configuration into a ConfigMap object. While this ConfigMap is not used during regular operation, you can +use it to show the outcome of a given values file. + +The unit tests use this ConfigMap to create an object with the configuration that can be asserted against. To run the +tests, use `helm test`. + +Be sure perform actual integration testing in a live environment in the main [k8s-monitoring](../..) chart. + +{{ template "chart.maintainersSection" . }} + + + +{{ template "chart.sourcesSection" . }} + + +{{ template "chart.requirementsSection" . }} + + + +{{ template "chart.valuesSection" . }} + diff --git a/grafana/charts/feature-cluster-metrics/charts/kepler-0.5.13.tgz b/grafana/charts/feature-cluster-metrics/charts/kepler-0.5.13.tgz new file mode 100644 index 0000000000000000000000000000000000000000..a9c447362f765293f2c8ca60ab239c051cfdf2fc GIT binary patch literal 5092 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 GY5)N77aU6f literal 0 HcmV?d00001 diff --git a/grafana/charts/feature-cluster-metrics/charts/kube-state-metrics-5.32.0.tgz b/grafana/charts/feature-cluster-metrics/charts/kube-state-metrics-5.32.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..bc685d5129a0f920053c442f90472265c6802b2b GIT binary patch literal 15241 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 ZJP*&q^FQ?Ye*pjh|NjghBp3iZ0RS1+`!WCk literal 0 HcmV?d00001 diff --git a/grafana/charts/feature-cluster-metrics/charts/prometheus-windows-exporter-0.10.0.tgz b/grafana/charts/feature-cluster-metrics/charts/prometheus-windows-exporter-0.10.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..2ada201d5db175aa9db330c4f82e37a79e1bfbcd GIT binary patch literal 8208 zcmV+rAn)HFiwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PKD3cH6j;VE^V*)JokOyT_tr=j)En?LFg;o!j15dgD(>NkSu@1xtR%nBr*vU3WfSYp#bEZr6}iE zh`}YzVsGt+_+mA=1(e~5F zPap4mH`;#kbm!rBFuGl{>pg{#gnu`>bz9BOeI*ac>95EIW!V@mb^?;;<)5SQ;V66( z#3&+8bE)6$!Y`Pl5Gl@pDdSM_4>b8Fn6nheFqbkH8;<`f`M)4Zf#UWGV72`3Jbn0d)R6zD+fTpA|GhkY*uyC)5(#Fs8$#V; ziZJNI>6{9n0tozV_vMShl<|~Ei7`xRf~vqCMhW2v7lczXNl<`fFhR(P5Eui^B!dMj zI7m$Mgh&)&5YUv&a2x<|oKYe9Vhpo+#6!yTyPOFsnR>fQWGb-(=)`0xR8PBS@$-o+212ca>2yQMaSPoDx%b;r=_1ps-GBu6Zv(P9h- z(?ceYI10>U01(p|3aQHl5zD4@HinOb03c#Xf{|oO9RUDfrf3t7;lUe=ig>$~V#@ep zD`Hl4J+Op1Dw5;`BaTvx;mzBi4+E>Udiwi7VKflBL{Doa*LjV}v`CWH%V3tU2}#D9 zR;LW+nB)+#G$)cyXhP)zE~%UYlXK)o=L@);(`XKbKrpq#CVHU;x0@vF5|HYuBm=@Z zSpb{D2dgp53ZEb)xqyxHKZ${miv%~ffYs{=$!Rtdu#qy33d59T3ft6HFirZs0ccUp zzISA+5ZGS&Wk-Ku{953<0M|iw4k$q1BV0~6X427IGGKP#O6h<(6H+1U03MfOqlUKM zhZE!%G*a|ZOjvMZH-ves@vX`z`=S_Jo0(@xAtdsHBU8pH2wM}BfQ4{^(ukG%Qw@^( zt)x#$c*(v%1YBa0z(!L*^`NPrWBBLoKkb;Njufn{NGHg(A`%{YaL8g*1(dzEKW#4# zNs11IRaj8f=YiX@}(?OdbOdFrX&%lUy%~G7rINj3H3n{Q{*JFx6z> z*>jqpA+1crGiwdhpz99yl`VU}c&(hw*T*junTUC1MqJEUk;H1u3pL_eA|g(5n$1EB z!5~{gDd}DrKgWA7P47UUu|hro_pUMz9*(Y@v}9u8uA6T+)3St$KR zm3LWVK0{^!JK@e#%Y+$TDo55sPq(xdb_r%P5Wtvtd0-j??hoEJDuW${O_HwNQu=AMundv@zCIxt`U4U@7_* zTzSjL6~WcNR1S)4PfKx}M}Mx%e)gbB{6(x9MlNop>I znv$W992H7CYg-PJg`4Sw@Y@_S5SLU&b4_W^Qs)A?s*-ttwlr`h{F0`+Ns0nEiXxFE z0QI@%V}hJ>R?Oy2a?QyFLQJQc*3$B%!T-5JIunv)5pG#}X%5YpRAlx&J6#V*wt$3X zGvszklG52+YG7nK#Yk$V{a-KOkHTPWY@EVc^S_2-d^?BaQXj~8nA+JuGw`W@*8d*Q!K^ zW`0y`r6bn|hu|2_iwO=q=@F7d=eE>Q-6aCaNhYSqh0`w9v;J!_L7t&hUI2@MWtIxY z282u9E7OW+e0__$%%Fx{_S8Ts9Uw)gl0K5z-}*J1yu--MS(kW0c33`-4|KKjW13gu zZN^_C)&+bid3?QmF>1& zQ0EW#lxlXQKO#~Kh&4#os|VsnpD1s+H?;4|Mt^p$G!Q)tCRwQm^`xPYbIc@-h(tXh zHomw2p0do^A$ZA@&dsK*3gCLa9%aLrMPg{o1I=c`nhG2CUBgR!d^L4elXt_Lg+Y)b ziLLh!Qn~*%dX*gF4XO#)K!zB*AQ?5@mQbTvY6vCP4K-tUDT+`CI!RFJc~!z=x>wfp zg^lS{oewk_Dg!vfOx42JD>fiGRkF78XxKLxpX0(w%iv;rphU7c^)dAE2zL77q-iG% zQ(bDSR8nb<<*0`pQzt8sg`6`^|84*YrP)g#or(s4dz?vN(F z2B};rHTe#^=aqf1b4nmnS-K)xek~l`kFMson&P?+0*!fWiN!B0V_dx!lBBuNfi2Dw z?SSeKtk(`lg@cWY$*N9nLfG1owG%vLl}y9)dIMvSygl8$D#)J*H8}u5u^gru7DVe=4_*sfMIvJSUu_D3J?m);URquMKQ$#%OO7_{;M|i@1we zOmM2GSUMG5223eXmJ(&*lVqVhSr;Mn!a{c5IK@j)^N5)6*mp&z6q8tl+Uhb+XEdv1 z?H!wFF16uw1(*sT7lbC7%`Pa>41IPc)BLPbpl9#c>(2oI_y0B%xs<$ros~*t4BJ7#(Pe`eC$JB{Arzv}YK>#W(iBw( zn4V4;SD~~wP}bJHR8u=7dj6-Bl@g1HWg?Ib(HbHq+1(CFWZ|;&+A6-&55^CZSvVaLEnl{=Idr*=3 zL1=-dv|6W)@?s1-qfu)AHtX(VcszPZZ4Zt4tX0@n75w54RdKhbx*J7mCTMD$SU<0_ z%fyA+Y&p+IRU;uW4#55@-5xVb^w%vLFw7Ln^w4>jC^dl$C}qhMuq_}44i!+&@t_cH z%H=Wy%A5?B7S*w2xpWCz+i8VY9ZNkQESGZxMg^yG@r-2>-)nN&bwJ}`*z|}w6Y_{N zHRhfd$ct=OycWpKa%}JL6n0;q{_^Vh;Ph|*`mbUkB&H_u!Yu5bG#b;+37?S2E*&3C zEp;rl{=1%$9{;@itYX%{hP7*B6ZCbkR@7sYHq@nXhYY3i_yYCEq4{0aJ(&{|7&c{d z(@{9stLFT=;?cogS*Z`ZLeN#e_XGFQEDPJn z(yn`{-+*Rx$}!$6IL&4!C76R*#>&_G?=dR$?A6vXuug0Y;1qc(s!sp|NQsQ*&$ZL# ze=r}O}zD+;j{FS?i<8RcgXDu#IIODB=w?mD zn+G|Iy*fsspVRkRnd%_EP%iaf{<;s5NtS>jpK%gvX0fjZN*Y8&66B50n;=shNH)L= z8mU>F8sDDbD9MSpOuiPPUO4xfU9EBl%3r&!?1a8nD2lOpf#ur07u7ZaM!~8OPCXUF z#jCUp=?pM~k_`cB8f~ji*!#f3x1mX^Je<{ry~B=ZlHc1ENof<2AT zi-W)J!vpb0^238xtJ=_sY7I;)@=DAqZY$9%k@|%R`729`6klo}4na54f7Y-S2LHpb zgf;~_YW`>U(|*w~Y0BImGJ$I4PF-gbY~QyiBtiisAO5h|A_l#avq zQm3&hkb=e-5pGfUh9|qAF(rdInx$33smZo7S**6iuvTKc9X<*lYLv{_o7Dl+h=-cj zw8tYYBuYLWD5Mq6!s6hOa>$F!i!|5*6<>6+#4^TSiRzbRX|EP%Iholw`ytElqr&Ty zJ##33{F$1_mhNh^=LZ>;&ng~~YL-MLC5f9P<}5CSxL(+VN&0#lpg(*)m(IKYM|oE5 z|0uKbhi7w4a^xbE`3<&$tls~zz4PeFqx$}jo$ZG^PrmK{xR2+Xe8alpZcU@@5 zEBw`LKJqs$z(=L@vk0C%)IVu@qFrj}4SHZmknv#)JdE_F; zXfq5BrnP(^XH9MR&Bkb|u&B=b)zLkLyv6of#CDOLir{ow(zm%W#L;o-_jSe~5ha}O zb$`Y`tv|>WjwNLbknq@$&D3>x)?Qu{Ik)HM2QkpQerm8xqwBL=_s<$5dLyhP$;PhL z=;~3nEMrR96{Ty9w60kVbF+Is<;`!GY4s5}<_U=qdjHge-dXSZqGmSbn9#-bur_rJ z+H*|OP|SzACu8{V0caK_MZ8|eLxoQ}(z_>OXvhKME$XgKG^;E0$$! z$)YRS-$QuFZBQoei-k4--mu9VYf+{$G2!Mi_?b@%PYJu0diF}`fnw_-LUqUe_u2nVJv0E?o>nYn5lL+!k)P z?eDX6oBY}qZ1{s1{~-QFEBaLx>y1|XYGI>cp*@vSuOrE9b0zNGCbk1Xhr>Oh=JAb( zw7w8`)X&>yNxf}ovg9Vj!lb1(m_?Iith=~J2cY?%`mo$)7PJ7 zXsDes-HI4Cecz=8{Gq6+deepVoI$7gO`R?q;C7%~tIxL5;6D290qodDmo*7;ow7G2 zag*9+2e4yyKQBf2JB-~LRg2X1@1X&pvq(fmSmQN$`Ae$#S~`<aA>9)FYn`*?i$CwVT0r4rcFV}642 zKbI0%BC9ne(3K5&TP>ibA*zb-^6$W8$-eOVbB!Lg7Y3^KpDgKFW0Qj})ZXH7jc!4i zFFtnLhiZG-yA~B%R8>!lvMbQ|Q&p{oO1a~s0pi9CQa0p958$dKcjY>E$FEn_t9Phj zk!l(2RmqM#`WsWNJxs0C%(84pN@g{+?1WD1nNmTOtnE_S>?X#+lybZzNfJ~U-8Q3c zU3Fn&_#QgyiCCHvrPbc3dD10vF~=n7!CS8kF`1&!JH*SuA+Iu851Q*J2( zH13E`Zx~EeygL80UQ_ds_qR(q)}Egl{hxk#_UiC-_uz2<`0Ql&aPQ|=|NHFatJjC8 zXGgCN4o`m=R$gKU7?-*1GCo6-%g8uIaTVkixJ#Ub2^A8v0f}RdLi{vd&TqBq-ORPi zXQHcQ2U~6LbQP@eR%biQ_Vv`OE!B+Iz^D@+eXL>=n2G*b~CHkZ|H*KetgDSrg(2-pTf4`Q1J{sb`Ca_3A9To<`7oJIx1gpa9wKdhYwKXIr1yoG{u`>Ium-A;@?ra39yj} zycATeToXt;b9gD7X3-|7X1eiGK=p!kFzp2E>RBl;^@?9YVj38H1tPNqgA0EHOs5I(O_Ql(jcQ1XoDaq}M_HrE8!tPplwc{gpm)>+k`8RbM_414SUc~+GvVI* zdSQLWMWf)+!QP7KWO?dE6+SLcweU%G+bC#xL_k%hIyK-g%T=Zdty?)n>*%9$7jxaUZYU>LYNZCbt&vyhF=v`yPd6d(7cL!msGq7UE7}4ItZF-b?mBx7uLk_OD|D> zdp_f{UjB!dT6lv5kSp@Po;-Tgxc_fwXY}~#xBQR$c-G2}wO1m5-uPDKi+C8C{{Qfy8lvu< zlD#X?aw}HHU6DPrCjFWhJ=9&<4hlZ0QPAdkS2gY`U8mt1lpJ@` z?zPS>cZPj%i)5;GS*~_dg{j(gd&M;pht_PlaaD+^+q^&Ix@{}?W>@#VJ2KwD7_5%& z*OyAyWw%B^-&+t^l{K?2eQF+XwX$)0$mOjURn6)mj60o;E@{7cnS_T&>z;{wz^A;2 z!kaNCpCuZwL-t5D+ui~ z^lyVt?J5h;OVelHt>wAvx)s32-4Y&1eZ=c(h_%Wd%;vQb*F>~Y{{~i&lT`S2P~Syy zGrIp53Vy6N|939X%{G8tG5_CwJlbxZ|F-?@{I`2~I`@Cs1oi)18$Z6#?k_jdHrGaU zOe^%==5|uT*PMp5mK`_rfnpo@M>qJMyF0xHo3N2F2^)GPpjFyktiHJkoAqU=rCFfv z;|dFAwhFJzBW-RmXy=fUJU=R5m$z@jx~Z-8$ibb=+V5wF-sgR;rT^`rRM#~FSLy$U zJ5QSN->0L|H~oJfkJTSadz9&N6B4=8z?N)fvR?;{fN;}**y6XaBP%wEe0htq&Q`+a z9woD@7XQ-QuKd++qyNG)kbjh=zw{q)-7md*(QoD1Y0E*jSN+zZ&1YFA zy2Wy1`gN@}uElG&@casS79R{8(o9FvslYanmc##QIPJ>Gs?_y4z_ zZa>`l=KtTv(}yD>C316Hq#10uoMQ%)f+jJ|W{{KUoXk*!LEl^-EQ(x*szD#30<(lo zjBiA<*_PH!l3t)rMe*K~EDrjRp}Cz4Hgb+r`W|DWe*W8LXfAnXnXai&f*iTN3pfnI zy_2&O$@J}f_Ns|rpPfKVxd_4;l|%inK|cs5f9FH}uX{0{4b?yHPjQhAD?k$xofkQn z8`ORb#bqA+7*5D}@M9>`Joxed1bz6GaLNh+2YdS>P&)D*MluL#jAUraarW+OR9&m& z|9F3Q@8y1&#RLk) z27y*L=02PWV^T;?askA<+ZEolk$$@|mogs@hchbY#Y6`gJU)+Dnid(Ai=pNCGuN@r z>PB2(84!3=-S|`jt<8@&tNVY;o3!8jf=OzMi}7%1ue8~8dKAocG(6Nd>-_~K99PHk zA7oP&1i%0Od&Dxq64V#s0LR>1yW7MFPuPN(MfwI-t>wcr-N}PYNRlL=uNr7~kJ`^~j`v^e z@1E?R9qzu|f7{vF;R=1_ccOMP@Y{{P`!="" checks) + {{- range $i := .Values.cadvisor.metricsTuning.normalizeUnnecessaryLabels }} + {{- range $label := $i.labels }} + rule { + source_labels = ["__name__", {{ $label | quote }}] + separator = "@" + regex = "{{ $i.metric }}@.*" + target_label = {{ $label | quote }} + replacement = "NA" + } + {{- end }} + {{- end }} +{{- end }} +{{- if .Values.cadvisor.metricsTuning.keepPhysicalFilesystemDevices }} + // Filter out non-physical devices/interfaces + rule { + source_labels = ["__name__", "device"] + separator = "@" + regex = "container_fs_.*@(/dev/)?({{ join "|" .Values.cadvisor.metricsTuning.keepPhysicalFilesystemDevices }})" + target_label = "__keepme" + replacement = "1" + } + rule { + source_labels = ["__name__", "__keepme"] + separator = "@" + regex = "container_fs_.*@" + action = "drop" + } + rule { + source_labels = ["__name__"] + regex = "container_fs_.*" + target_label = "__keepme" + replacement = "" + } +{{- end }} +{{- if .Values.cadvisor.metricsTuning.keepPhysicalNetworkDevices }} + rule { + source_labels = ["__name__", "interface"] + separator = "@" + regex = "container_network_.*@({{ join "|" .Values.cadvisor.metricsTuning.keepPhysicalNetworkDevices }})" + target_label = "__keepme" + replacement = "1" + } + rule { + source_labels = ["__name__", "__keepme"] + separator = "@" + regex = "container_network_.*@" + action = "drop" + } + rule { + source_labels = ["__name__"] + regex = "container_network_.*" + target_label = "__keepme" + replacement = "" + } +{{- end }} +{{- if .Values.cadvisor.metricsTuning.includeNamespaces }} + rule { + source_labels = ["namespace"] + regex = {{ .Values.cadvisor.metricsTuning.includeNamespaces | join "|" | quote }} + action = "keep" + } +{{- end }} +{{- if .Values.cadvisor.metricsTuning.excludeNamespaces }} + rule { + source_labels = ["namespace"] + regex = {{ .Values.cadvisor.metricsTuning.excludeNamespaces | join "|" | quote }} + action = "drop" + } +{{- end }} +{{- if .Values.cadvisor.extraMetricProcessingRules }} +{{ .Values.cadvisor.extraMetricProcessingRules | indent 2 }} +{{- end }} + forward_to = argument.metrics_destinations.value +} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-cluster-metrics/templates/_helpers.tpl b/grafana/charts/feature-cluster-metrics/templates/_helpers.tpl new file mode 100644 index 0000000..36b79ae --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/templates/_helpers.tpl @@ -0,0 +1,17 @@ +{{/* +Create a default fully qualified 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 "feature.clusterMetrics.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" | lower }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride | lower }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" | lower }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" | lower }} +{{- end }} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-cluster-metrics/templates/_kepler.alloy.tpl b/grafana/charts/feature-cluster-metrics/templates/_kepler.alloy.tpl new file mode 100644 index 0000000..de5cd88 --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/templates/_kepler.alloy.tpl @@ -0,0 +1,79 @@ +{{ define "feature.clusterMetrics.kepler.allowList" }} +{{- $allowList := list }} +{{ if .Values.kepler.metricsTuning.useDefaultAllowList }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") (.Files.Get "default-allow-lists/kepler.yaml" | fromYamlArray) -}} +{{ end }} +{{ if .Values.kepler.metricsTuning.includeMetrics }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") .Values.kepler.metricsTuning.includeMetrics -}} +{{ end }} +{{ $allowList | uniq | toYaml }} +{{ end }} + +{{- define "feature.clusterMetrics.kepler.alloy" }} +{{- if .Values.kepler.enabled }} +{{- $metricAllowList := include "feature.clusterMetrics.kepler.allowList" . | fromYamlArray }} +{{- $metricDenyList := .Values.kepler.metricsTuning.excludeMetrics }} +{{- $labelSelectors := list }} +{{- range $k, $v := .Values.kepler.labelMatchers }} +{{- $labelSelectors = append $labelSelectors (printf "%s=%s" $k $v) }} +{{- end }} + +discovery.kubernetes "kepler" { + role = "pod" + namespaces { + own_namespace = true + } + selectors { + role = "pod" + label = {{ $labelSelectors | join "," | quote }} + } +} + +discovery.relabel "kepler" { + targets = discovery.kubernetes.kepler.targets + rule { + source_labels = ["__meta_kubernetes_pod_node_name"] + action = "replace" + target_label = "instance" + } +{{- if .Values.kepler.extraDiscoveryRules }} +{{ .Values.kepler.extraDiscoveryRules | indent 2 }} +{{- end }} +} + +prometheus.scrape "kepler" { + targets = discovery.relabel.kepler.output + job_name = {{ .Values.kepler.jobLabel | quote }} + honor_labels = true + scrape_interval = {{ .Values.kepler.scrapeInterval | default .Values.global.scrapeInterval | quote }} + clustering { + enabled = true + } +{{- if or $metricAllowList $metricDenyList .Values.kepler.extraMetricProcessingRules }} + forward_to = [prometheus.relabel.kepler.receiver] +} + +prometheus.relabel "kepler" { + max_cache_size = {{ .Values.kepler.maxCacheSize | default .Values.global.maxCacheSize | int }} +{{- if $metricAllowList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricAllowList | join "|" | quote }} + action = "keep" + } +{{- end }} +{{- if $metricDenyList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricDenyList | join "|" | quote }} + action = "drop" + } +{{- end }} +{{- if .Values.kepler.extraMetricProcessingRules }} +{{ .Values.kepler.extraMetricProcessingRules | indent 2 }} +{{- end }} +{{- end }} + forward_to = argument.metrics_destinations.value +} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-cluster-metrics/templates/_kube_controller_manager.alloy.tpl b/grafana/charts/feature-cluster-metrics/templates/_kube_controller_manager.alloy.tpl new file mode 100644 index 0000000..4e9e911 --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/templates/_kube_controller_manager.alloy.tpl @@ -0,0 +1,68 @@ +{{- define "feature.clusterMetrics.kubeControllerManager.alloy" }} +{{- if or .Values.kubeControllerManager.enabled (and .Values.controlPlane.enabled (not (eq .Values.kubeControllerManager.enabled false))) }} +{{- $metricAllowList := .Values.kubeControllerManager.metricsTuning.includeMetrics }} +{{- $metricDenyList := .Values.kubeControllerManager.metricsTuning.excludeMetrics }} + +discovery.kubernetes "kube_controller_manager" { + role = "pod" + namespaces { + names = ["kube-system"] + } + selectors { + role = "pod" + label = {{ .Values.kubeControllerManager.selectorLabel | quote }} + } +} + +discovery.relabel "kube_controller_manager" { + targets = discovery.kubernetes.kube_controller_manager.targets + rule { + source_labels = ["__address__"] + replacement = "$1:{{ .Values.kubeControllerManager.port }}" + target_label = "__address__" + } +{{- if .Values.kubeControllerManager.extraDiscoveryRules }} +{{ .Values.kubeControllerManager.extraDiscoveryRules | indent 2 }} +{{- end }} +} + +prometheus.scrape "kube_controller_manager" { + targets = discovery.relabel.kube_controller_manager.output + job_name = {{ .Values.kubeControllerManager.jobLabel | quote }} + scheme = "https" + scrape_interval = {{ .Values.kubeControllerManager.scrapeInterval | default .Values.global.scrapeInterval | quote }} + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + tls_config { + insecure_skip_verify = true + } + clustering { + enabled = true + } +{{- if or $metricAllowList $metricDenyList .Values.kubeControllerManager.extraMetricProcessingRules }} + forward_to = [prometheus.relabel.kube_controller_manager.receiver] +} + +prometheus.relabel "kube_controller_manager" { + max_cache_size = {{ .Values.kubeControllerManager.maxCacheSize | default .Values.global.maxCacheSize | int }} +{{- if $metricAllowList }} + rule { + source_labels = ["__name__"] + regex = "up|scrape_samples_scraped|{{ $metricAllowList | join "|" }}" + action = "keep" + } +{{- end }} +{{- if $metricDenyList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricDenyList | join "|" | quote }} + action = "drop" + } +{{- end }} +{{- if .Values.kubeControllerManager.extraMetricProcessingRules }} +{{ .Values.kubeControllerManager.extraMetricProcessingRules | indent 2 }} +{{- end }} +{{- end }} + forward_to = argument.metrics_destinations.value +} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-cluster-metrics/templates/_kube_dns.alloy.tpl b/grafana/charts/feature-cluster-metrics/templates/_kube_dns.alloy.tpl new file mode 100644 index 0000000..b91b39d --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/templates/_kube_dns.alloy.tpl @@ -0,0 +1,140 @@ +{{- define "feature.clusterMetrics.kubeDNS.alloy" }} +{{- if or .Values.kubeDNS.enabled (and .Values.controlPlane.enabled (not (eq .Values.kubeDNS.enabled false))) }} +{{- $metricAllowList := .Values.kubeDNS.metricsTuning.includeMetrics }} +{{- $metricDenyList := .Values.kubeDNS.metricsTuning.excludeMetrics }} + +// KubeDNS +discovery.kubernetes "kube_dns" { + role = "endpoints" + namespaces { + names = ["kube-system"] + } + selectors { + role = "endpoints" + label = "k8s-app=kube-dns" + } +} + +discovery.relabel "kube_dns" { + targets = discovery.kubernetes.kube_dns.targets + + // keep only the specified metrics port name, and pods that are Running and ready + rule { + source_labels = [ + "__meta_kubernetes_pod_container_port_name", + "__meta_kubernetes_pod_phase", + "__meta_kubernetes_pod_ready", + ] + separator = "@" + regex = "metrics@Running@true" + action = "keep" + } + + // drop any init containers + rule { + source_labels = ["__meta_kubernetes_pod_container_init"] + regex = "true" + action = "drop" + } + + // set the namespace label + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + + // set the pod label + rule { + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + + // set the container label + rule { + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + + // set a workload label + rule { + source_labels = [ + "__meta_kubernetes_pod_controller_kind", + "__meta_kubernetes_pod_controller_name", + ] + separator = "/" + target_label = "workload" + } + // remove the hash from the ReplicaSet + rule { + source_labels = ["workload"] + regex = "(ReplicaSet/.+)-.+" + target_label = "workload" + } + + // set the app name if specified as metadata labels "app:" or "app.kubernetes.io/name:" or "k8s-app:" + rule { + action = "replace" + source_labels = [ + "__meta_kubernetes_pod_label_app_kubernetes_io_name", + "__meta_kubernetes_pod_label_k8s_app", + "__meta_kubernetes_pod_label_app", + ] + separator = ";" + regex = "^(?:;*)?([^;]+).*$" + replacement = "$1" + target_label = "app" + } + + // set the service label + rule { + source_labels = ["__meta_kubernetes_service_name"] + target_label = "service" + } + + // set a source label + rule { + action = "replace" + replacement = "kubernetes" + target_label = "source" + } +{{- if .Values.kubeDNS.extraDiscoveryRules }} +{{ .Values.kubeDNS.extraDiscoveryRules | indent 2 }} +{{- end }} +} + +prometheus.scrape "kube_dns" { + targets = discovery.relabel.kube_dns.output + job_name = {{ .Values.kubeDNS.jobLabel | quote }} + scheme = "http" + scrape_interval = {{ .Values.kubeDNS.scrapeInterval | default .Values.global.scrapeInterval | quote }} + clustering { + enabled = true + } +{{- if or $metricAllowList $metricDenyList .Values.kubeDNS.extraMetricProcessingRules }} + forward_to = [prometheus.relabel.kube_dns.receiver] +} + +prometheus.relabel "kube_dns" { + max_cache_size = {{ .Values.kubeDNS.maxCacheSize | default .Values.global.maxCacheSize | int }} +{{- if $metricAllowList }} + rule { + source_labels = ["__name__"] + regex = "up|scrape_samples_scraped|{{ $metricAllowList | join "|" }}" + action = "keep" + } +{{- end }} +{{- if $metricDenyList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricDenyList | join "|" | quote }} + action = "drop" + } +{{- end }} +{{- if .Values.kubeDNS.extraMetricProcessingRules }} +{{ .Values.kubeDNS.extraMetricProcessingRules | indent 2 }} +{{- end }} +{{- end }} + forward_to = argument.metrics_destinations.value +} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-cluster-metrics/templates/_kube_proxy.alloy.tpl b/grafana/charts/feature-cluster-metrics/templates/_kube_proxy.alloy.tpl new file mode 100644 index 0000000..5197700 --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/templates/_kube_proxy.alloy.tpl @@ -0,0 +1,64 @@ +{{- define "feature.clusterMetrics.kubeProxy.alloy" }} +{{- if or .Values.kubeProxy.enabled (and .Values.controlPlane.enabled (not (eq .Values.kubeProxy.enabled false))) }} +{{- $metricAllowList := .Values.kubeProxy.metricsTuning.includeMetrics }} +{{- $metricDenyList := .Values.kubeProxy.metricsTuning.excludeMetrics }} + +discovery.kubernetes "kube_proxy" { + role = "pod" + namespaces { + names = ["kube-system"] + } + selectors { + role = "pod" + label = {{ .Values.kubeProxy.selectorLabel | quote }} + } +} + +discovery.relabel "kube_proxy" { + targets = discovery.kubernetes.kube_proxy.targets + rule { + source_labels = ["__address__"] + replacement = "$1:{{ .Values.kubeProxy.port }}" + target_label = "__address__" + } +{{- if .Values.kubeProxy.extraDiscoveryRules }} +{{ .Values.kubeProxy.extraDiscoveryRules | indent 2 }} +{{- end }} +} + +prometheus.scrape "kube_proxy" { + targets = discovery.relabel.kube_proxy.output + job_name = {{ .Values.kubeProxy.jobLabel | quote }} + scheme = "http" + scrape_interval = {{ .Values.kubeProxy.scrapeInterval | default .Values.global.scrapeInterval | quote }} + clustering { + enabled = true + } +{{- if or $metricAllowList $metricDenyList .Values.kubeProxy.extraMetricProcessingRules }} + forward_to = [prometheus.relabel.kube_proxy.receiver] +} + +prometheus.relabel "kube_proxy" { + max_cache_size = {{ .Values.kubeProxy.maxCacheSize | default .Values.global.maxCacheSize | int }} +{{- if $metricAllowList }} + rule { + source_labels = ["__name__"] + regex = "up|scrape_samples_scraped|{{ $metricAllowList | join "|" }}" + action = "keep" + } +{{- end }} +{{- if $metricDenyList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricDenyList | join "|" | quote }} + action = "drop" + } +{{- end }} +{{- if .Values.kubeProxy.extraMetricProcessingRules }} +{{ .Values.kubeProxy.extraMetricProcessingRules | indent 2 }} +{{- end }} +{{- end }} + forward_to = argument.metrics_destinations.value +} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-cluster-metrics/templates/_kube_scheduler.alloy.tpl b/grafana/charts/feature-cluster-metrics/templates/_kube_scheduler.alloy.tpl new file mode 100644 index 0000000..1c3ad1e --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/templates/_kube_scheduler.alloy.tpl @@ -0,0 +1,68 @@ +{{- define "feature.clusterMetrics.kubeScheduler.alloy" }} +{{- if or .Values.kubeScheduler.enabled (and .Values.controlPlane.enabled (not (eq .Values.kubeScheduler.enabled false))) }} +{{- $metricAllowList := .Values.kubeScheduler.metricsTuning.includeMetrics }} +{{- $metricDenyList := .Values.kubeScheduler.metricsTuning.excludeMetrics }} + +discovery.kubernetes "kube_scheduler" { + role = "pod" + namespaces { + names = ["kube-system"] + } + selectors { + role = "pod" + label = {{ .Values.kubeScheduler.selectorLabel | quote }} + } +} + +discovery.relabel "kube_scheduler" { + targets = discovery.kubernetes.kube_scheduler.targets + rule { + source_labels = ["__address__"] + replacement = "$1:{{ .Values.kubeScheduler.port }}" + target_label = "__address__" + } +{{- if .Values.kubeScheduler.extraDiscoveryRules }} +{{ .Values.kubeScheduler.extraDiscoveryRules | indent 2 }} +{{- end }} +} + +prometheus.scrape "kube_scheduler" { + targets = discovery.relabel.kube_scheduler.output + job_name = {{ .Values.kubeScheduler.jobLabel | quote }} + scheme = "https" + scrape_interval = {{ .Values.kubeScheduler.scrapeInterval | default .Values.global.scrapeInterval | quote }} + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + tls_config { + insecure_skip_verify = true + } + clustering { + enabled = true + } +{{- if or $metricAllowList $metricDenyList .Values.kubeScheduler.extraMetricProcessingRules }} + forward_to = [prometheus.relabel.kube_scheduler.receiver] +} + +prometheus.relabel "kube_scheduler" { + max_cache_size = {{ .Values.kubeScheduler.maxCacheSize | default .Values.global.maxCacheSize | int }} +{{- if $metricAllowList }} + rule { + source_labels = ["__name__"] + regex = "up|scrape_samples_scraped|{{ $metricAllowList | join "|" }}" + action = "keep" + } +{{- end }} +{{- if $metricDenyList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricDenyList | join "|" | quote }} + action = "drop" + } +{{- end }} +{{- if .Values.kubeScheduler.extraMetricProcessingRules }} +{{ .Values.kubeScheduler.extraMetricProcessingRules | indent 2 }} +{{- end }} +{{- end }} + forward_to = argument.metrics_destinations.value +} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-cluster-metrics/templates/_kube_state_metrics.alloy.tpl b/grafana/charts/feature-cluster-metrics/templates/_kube_state_metrics.alloy.tpl new file mode 100644 index 0000000..808aac8 --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/templates/_kube_state_metrics.alloy.tpl @@ -0,0 +1,102 @@ +{{ define "feature.clusterMetrics.kube_state_metrics.allowList" }} +{{- $allowList := list }} +{{ if (index .Values "kube-state-metrics").metricsTuning.useDefaultAllowList }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") (.Files.Get "default-allow-lists/kube-state-metrics.yaml" | fromYamlArray) -}} +{{ end }} +{{ if (index .Values "kube-state-metrics").metricsTuning.includeMetrics }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") (index .Values "kube-state-metrics").metricsTuning.includeMetrics -}} +{{ end }} +{{ $allowList | uniq | toYaml }} +{{ end }} + +{{- define "feature.clusterMetrics.kube_state_metrics.alloy" }} +{{- if (index .Values "kube-state-metrics").enabled }} +{{- $metricAllowList := include "feature.clusterMetrics.kube_state_metrics.allowList" . | fromYamlArray }} +{{- $metricDenyList := (index .Values "kube-state-metrics").metricsTuning.excludeMetrics }} +{{- $labelSelectors := list }} +{{- range $label, $value := (index .Values "kube-state-metrics").labelMatchers }} + {{- $labelSelectors = append $labelSelectors (printf "%s=%s" $label $value) }} +{{- end }} +{{- if (index .Values "kube-state-metrics").deploy }} + {{- $labelSelectors = append $labelSelectors (printf "release=%s" .Release.Name) }} +{{- end }} +discovery.kubernetes "kube_state_metrics" { + role = "{{ (index .Values "kube-state-metrics").discoveryType }}" + + selectors { + role = "{{ (index .Values "kube-state-metrics").discoveryType }}" + label = {{ $labelSelectors | join "," | quote }} + } +{{- if (index .Values "kube-state-metrics").deploy }} + namespaces { + names = [{{ .Release.Namespace | quote }}] + } +{{- else if (index .Values "kube-state-metrics").namespace }} + namespaces { + names = [{{ (index .Values "kube-state-metrics").namespace | quote }}] + } +{{- end }} +} + +discovery.relabel "kube_state_metrics" { + targets = discovery.kubernetes.kube_state_metrics.targets + + // only keep targets with a matching port name + rule { + source_labels = ["__meta_kubernetes_pod_container_port_name"] + regex = {{ (index .Values "kube-state-metrics").service.portName | quote }} + action = "keep" + } + + rule { + action = "replace" + replacement = "kubernetes" + target_label = "source" + } + {{- (index .Values "kube-state-metrics").extraDiscoveryRules | nindent 2 }} +} + +prometheus.scrape "kube_state_metrics" { + targets = discovery.relabel.kube_state_metrics.output + job_name = {{ (index .Values "kube-state-metrics").jobLabel | quote }} + scrape_interval = {{ (index .Values "kube-state-metrics").scrapeInterval | default .Values.global.scrapeInterval | quote }} + scheme = {{ (index .Values "kube-state-metrics").service.scheme | quote }} + bearer_token_file = {{ (index .Values "kube-state-metrics").bearerTokenFile | quote }} + tls_config { + insecure_skip_verify = true + } + + clustering { + enabled = true + } + +{{- if or $metricAllowList $metricDenyList (index .Values "kube-state-metrics").extraMetricProcessingRules }} + forward_to = [prometheus.relabel.kube_state_metrics.receiver] +} + +prometheus.relabel "kube_state_metrics" { + max_cache_size = {{ (index .Values "kube-state-metrics").maxCacheSize | default .Values.global.maxCacheSize | int }} + +{{- if $metricAllowList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricAllowList | join "|" | quote }} + action = "keep" + } +{{- end }} +{{- if $metricDenyList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricDenyList | join "|" | quote }} + action = "drop" + } +{{- end }} + +{{- if (index .Values "kube-state-metrics").extraMetricProcessingRules }} + {{ (index .Values "kube-state-metrics").extraMetricProcessingRules | nindent 2}} +{{- end }} +{{- end }} + forward_to = argument.metrics_destinations.value +} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-cluster-metrics/templates/_kubelet.alloy.tpl b/grafana/charts/feature-cluster-metrics/templates/_kubelet.alloy.tpl new file mode 100644 index 0000000..d016801 --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/templates/_kubelet.alloy.tpl @@ -0,0 +1,107 @@ +{{ define "feature.clusterMetrics.kubelet.allowList" }} +{{- $allowList := list }} +{{ if .Values.kubelet.metricsTuning.useDefaultAllowList }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") (.Files.Get "default-allow-lists/kubelet.yaml" | fromYamlArray) -}} +{{ end }} +{{ if .Values.kubelet.metricsTuning.includeMetrics }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") .Values.kubelet.metricsTuning.includeMetrics -}} +{{ end }} +{{ $allowList | uniq | toYaml }} +{{ end }} + +{{- define "feature.clusterMetrics.kubelet.alloy" }} +{{- if .Values.kubelet.enabled }} +{{- $metricAllowList := include "feature.clusterMetrics.kubelet.allowList" . | fromYamlArray }} +{{- $metricDenyList := .Values.kubelet.metricsTuning.excludeMetrics }} + +// Kubelet +discovery.relabel "kubelet" { + targets = discovery.kubernetes.nodes.targets +{{- if eq .Values.kubelet.nodeAddressFormat "proxy" }} + rule { + target_label = "__address__" + replacement = "{{ .Values.global.kubernetesAPIService | default "kubernetes.default.svc.cluster.local:443" }}" + } + rule { + source_labels = ["__meta_kubernetes_node_name"] + regex = "(.+)" + replacement = "/api/v1/nodes/${1}/proxy/metrics" + target_label = "__metrics_path__" + } + // set the node label + rule { + source_labels = ["__meta_kubernetes_node_name"] + target_label = "node" + } + + // set the app name if specified as metadata labels "app:" or "app.kubernetes.io/name:" or "k8s-app:" + rule { + action = "replace" + source_labels = [ + "__meta_kubernetes_node_label_app_kubernetes_io_name", + "__meta_kubernetes_node_label_k8s_app", + "__meta_kubernetes_node_label_app", + ] + separator = ";" + regex = "^(?:;*)?([^;]+).*$" + replacement = "$1" + target_label = "app" + } + + // set a source label + rule { + action = "replace" + replacement = "kubernetes" + target_label = "source" + } +{{- end }} +{{- if .Values.kubelet.extraDiscoveryRules }} +{{ .Values.kubelet.extraDiscoveryRules | indent 2 }} +{{- end }} +} + +prometheus.scrape "kubelet" { + targets = discovery.relabel.kubelet.output + job_name = {{ .Values.kubelet.jobLabel | quote }} + scheme = "https" + scrape_interval = {{ .Values.kubelet.scrapeInterval | default .Values.global.scrapeInterval | quote }} + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + + tls_config { + ca_file = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" + insecure_skip_verify = true + server_name = "kubernetes" + } + + clustering { + enabled = true + } + + forward_to = [prometheus.relabel.kubelet.receiver] +} + +prometheus.relabel "kubelet" { + max_cache_size = {{ .Values.kubelet.maxCacheSize | default .Values.global.maxCacheSize | int }} + +{{- if $metricAllowList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricAllowList | join "|" | quote }} + action = "keep" + } +{{- end }} +{{- if $metricDenyList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricDenyList | join "|" | quote }} + action = "drop" + } +{{- end }} +{{- if .Values.kubelet.extraMetricProcessingRules }} + {{ .Values.kubelet.extraMetricProcessingRules | indent 2 }} +{{- end }} + + forward_to = argument.metrics_destinations.value +} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-cluster-metrics/templates/_kubelet_probes.alloy.tpl b/grafana/charts/feature-cluster-metrics/templates/_kubelet_probes.alloy.tpl new file mode 100644 index 0000000..b41e2cb --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/templates/_kubelet_probes.alloy.tpl @@ -0,0 +1,112 @@ +{{ define "feature.clusterMetrics.kubeletProbes.allowList" }} +{{- $allowList := list }} +{{ if .Values.kubeletProbes.metricsTuning.useDefaultAllowList }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") (.Files.Get "default-allow-lists/kubelet_probes.yaml" | fromYamlArray) -}} +{{ end }} +{{ if .Values.kubeletProbes.metricsTuning.includeMetrics }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") .Values.kubeletProbes.metricsTuning.includeMetrics -}} +{{ end }} +{{ $allowList | uniq | toYaml }} +{{ end }} + +{{- define "feature.clusterMetrics.kubeletProbes.alloy" }} +{{- if .Values.kubeletProbes.enabled }} +{{- $metricAllowList := include "feature.clusterMetrics.kubeletProbes.allowList" . | fromYamlArray }} +{{- $metricDenyList := .Values.kubeletProbes.metricsTuning.excludeMetrics }} + +// Kubelet Probes +discovery.relabel "kubelet_probes" { + targets = discovery.kubernetes.nodes.targets +{{- if eq .Values.kubeletProbes.nodeAddressFormat "proxy" }} + rule { + target_label = "__address__" + replacement = "{{ .Values.global.kubernetesAPIService | default "kubernetes.default.svc.cluster.local:443" }}" + } + rule { + source_labels = ["__meta_kubernetes_node_name"] + regex = "(.+)" + replacement = "/api/v1/nodes/${1}/proxy/metrics/probes" + target_label = "__metrics_path__" + } +{{ else if eq .Values.kubeletProbes.nodeAddressFormat "direct" }} + rule { + replacement = "/metrics/probes" + target_label = "__metrics_path__" + } +{{- end }} + // set the node label + rule { + source_labels = ["__meta_kubernetes_node_name"] + target_label = "node" + } + + // set the app name if specified as metadata labels "app:" or "app.kubernetes.io/name:" or "k8s-app:" + rule { + action = "replace" + source_labels = [ + "__meta_kubernetes_node_label_app_kubernetes_io_name", + "__meta_kubernetes_node_label_k8s_app", + "__meta_kubernetes_node_label_app", + ] + separator = ";" + regex = "^(?:;*)?([^;]+).*$" + replacement = "$1" + target_label = "app" + } + + // set a source label + rule { + action = "replace" + replacement = "kubernetes" + target_label = "source" + } +{{- if .Values.kubeletProbes.extraRelabelingRules }} +{{ .Values.kubeletProbes.extraRelabelingRules | indent 2 }} +{{- end }} +} + +prometheus.scrape "kubelet_probes" { + targets = discovery.relabel.kubelet_probes.output + job_name = {{ .Values.kubeletProbes.jobLabel | quote }} + scheme = "https" + scrape_interval = {{ .Values.kubeletProbes.scrapeInterval | default .Values.global.scrapeInterval | quote }} + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + + tls_config { + ca_file = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" + insecure_skip_verify = true + server_name = "kubernetes" + } + + clustering { + enabled = true + } + + forward_to = [prometheus.relabel.kubelet_probes.receiver] +} + +prometheus.relabel "kubelet_probes" { + max_cache_size = {{ .Values.kubeletProbes.maxCacheSize | default .Values.global.maxCacheSize | int }} + +{{- if $metricAllowList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricAllowList | join "|" | quote }} + action = "keep" + } +{{- end }} +{{- if $metricDenyList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricDenyList | join "|" | quote }} + action = "drop" + } +{{- end }} +{{- if .Values.kubeletProbes.extraMetricProcessingRules }} + {{ .Values.kubeletProbes.extraMetricProcessingRules | indent 2 }} +{{- end }} + + forward_to = argument.metrics_destinations.value +} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-cluster-metrics/templates/_kubelet_resource.alloy.tpl b/grafana/charts/feature-cluster-metrics/templates/_kubelet_resource.alloy.tpl new file mode 100644 index 0000000..05030a4 --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/templates/_kubelet_resource.alloy.tpl @@ -0,0 +1,112 @@ +{{ define "feature.clusterMetrics.kubeletResource.allowList" }} +{{- $allowList := list }} +{{ if .Values.kubeletResource.metricsTuning.useDefaultAllowList }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") (.Files.Get "default-allow-lists/kubelet_resource.yaml" | fromYamlArray) -}} +{{ end }} +{{ if .Values.kubeletResource.metricsTuning.includeMetrics }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") .Values.kubeletResource.metricsTuning.includeMetrics -}} +{{ end }} +{{ $allowList | uniq | toYaml }} +{{ end }} + +{{- define "feature.clusterMetrics.kubeletResource.alloy" }} +{{- if .Values.kubeletResource.enabled }} +{{- $metricAllowList := include "feature.clusterMetrics.kubeletResource.allowList" . | fromYamlArray }} +{{- $metricDenyList := .Values.kubeletResource.metricsTuning.excludeMetrics }} + +// Kubelet Resources +discovery.relabel "kubelet_resources" { + targets = discovery.kubernetes.nodes.targets +{{- if eq .Values.kubeletResource.nodeAddressFormat "proxy" }} + rule { + target_label = "__address__" + replacement = "{{ .Values.global.kubernetesAPIService | default "kubernetes.default.svc.cluster.local:443" }}" + } + rule { + source_labels = ["__meta_kubernetes_node_name"] + regex = "(.+)" + replacement = "/api/v1/nodes/${1}/proxy/metrics/resource" + target_label = "__metrics_path__" + } +{{ else if eq .Values.kubeletResource.nodeAddressFormat "direct" }} + rule { + replacement = "/metrics/resource" + target_label = "__metrics_path__" + } +{{- end }} + // set the node label + rule { + source_labels = ["__meta_kubernetes_node_name"] + target_label = "node" + } + + // set the app name if specified as metadata labels "app:" or "app.kubernetes.io/name:" or "k8s-app:" + rule { + action = "replace" + source_labels = [ + "__meta_kubernetes_node_label_app_kubernetes_io_name", + "__meta_kubernetes_node_label_k8s_app", + "__meta_kubernetes_node_label_app", + ] + separator = ";" + regex = "^(?:;*)?([^;]+).*$" + replacement = "$1" + target_label = "app" + } + + // set a source label + rule { + action = "replace" + replacement = "kubernetes" + target_label = "source" + } +{{- if .Values.kubeletResource.extraRelabelingRules }} +{{ .Values.kubeletResource.extraRelabelingRules | indent 2 }} +{{- end }} +} + +prometheus.scrape "kubelet_resources" { + targets = discovery.relabel.kubelet_resources.output + job_name = {{ .Values.kubeletResource.jobLabel | quote }} + scheme = "https" + scrape_interval = {{ .Values.kubeletResource.scrapeInterval | default .Values.global.scrapeInterval | quote }} + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + + tls_config { + ca_file = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" + insecure_skip_verify = true + server_name = "kubernetes" + } + + clustering { + enabled = true + } + + forward_to = [prometheus.relabel.kubelet_resources.receiver] +} + +prometheus.relabel "kubelet_resources" { + max_cache_size = {{ .Values.kubeletResource.maxCacheSize | default .Values.global.maxCacheSize | int }} + +{{- if $metricAllowList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricAllowList | join "|" | quote }} + action = "keep" + } +{{- end }} +{{- if $metricDenyList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricDenyList | join "|" | quote }} + action = "drop" + } +{{- end }} +{{- if .Values.kubeletResource.extraMetricProcessingRules }} + {{ .Values.kubeletResource.extraMetricProcessingRules | indent 2 }} +{{- end }} + + forward_to = argument.metrics_destinations.value +} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-cluster-metrics/templates/_module.alloy.tpl b/grafana/charts/feature-cluster-metrics/templates/_module.alloy.tpl new file mode 100644 index 0000000..7ee2d50 --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/templates/_module.alloy.tpl @@ -0,0 +1,34 @@ +{{- define "feature.clusterMetrics.module" }} +{{- $discoverNodes := false }} +{{- $discoverNodes = or $discoverNodes .Values.cadvisor.enabled }} +{{- $discoverNodes = or $discoverNodes .Values.kubelet.enabled }} +{{- $discoverNodes = or $discoverNodes .Values.kubeletResource.enabled }} +{{- $discoverNodes = or $discoverNodes .Values.kubeletProbes.enabled }} +declare "cluster_metrics" { + argument "metrics_destinations" { + comment = "Must be a list of metric destinations where collected metrics should be forwarded to" + } + + {{- if $discoverNodes }} + discovery.kubernetes "nodes" { + role = "node" + } + {{- end }} + {{- include "feature.clusterMetrics.kubelet.alloy" . | indent 2 }} + {{- include "feature.clusterMetrics.kubeletResource.alloy" . | indent 2 }} + {{- include "feature.clusterMetrics.kubeletProbes.alloy" . | indent 2 }} + {{- include "feature.clusterMetrics.cadvisor.alloy" . | indent 2 }} + {{- include "feature.clusterMetrics.apiServer.alloy" . | indent 2 }} + {{- include "feature.clusterMetrics.kubeControllerManager.alloy" . | indent 2 }} + {{- include "feature.clusterMetrics.kubeDNS.alloy" . | indent 2 }} + {{- include "feature.clusterMetrics.kubeProxy.alloy" . | indent 2 }} + {{- include "feature.clusterMetrics.kubeScheduler.alloy" . | indent 2 }} + {{- include "feature.clusterMetrics.kube_state_metrics.alloy" . | indent 2 }} + {{- include "feature.clusterMetrics.node_exporter.alloy" . | indent 2 }} + {{- include "feature.clusterMetrics.windows_exporter.alloy" . | indent 2 }} + {{- include "feature.clusterMetrics.kepler.alloy" . | indent 2 }} + {{- include "feature.clusterMetrics.opencost.alloy" . | indent 2 }} +} +{{- end -}} + +{{- define "feature.clusterMetrics.alloyModules" }}{{- end }} diff --git a/grafana/charts/feature-cluster-metrics/templates/_node_exporter.alloy.tpl b/grafana/charts/feature-cluster-metrics/templates/_node_exporter.alloy.tpl new file mode 100644 index 0000000..f0572df --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/templates/_node_exporter.alloy.tpl @@ -0,0 +1,195 @@ +{{- define "feature.clusterMetrics.node_exporter.allowList" }} +{{- $allowList := list }} +{{ if (index .Values "node-exporter").metricsTuning.useDefaultAllowList }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") (.Files.Get "default-allow-lists/node-exporter.yaml" | fromYamlArray) -}} +{{ end }} +{{ if (index .Values "node-exporter").metricsTuning.useIntegrationAllowList }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") (.Files.Get "default-allow-lists/node-exporter-integration.yaml" | fromYamlArray) -}} +{{ end }} +{{ if (index .Values "node-exporter").metricsTuning.includeMetrics }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") (index .Values "node-exporter").metricsTuning.includeMetrics -}} +{{ end }} +{{ $allowList | uniq | toYaml }} +{{- end }} + +{{- define "feature.clusterMetrics.node_exporter.alloy" }} +{{- if (index .Values "node-exporter").enabled }} +{{- $metricAllowList := include "feature.clusterMetrics.node_exporter.allowList" . | fromYamlArray }} +{{- $metricDenyList := (index .Values "node-exporter").metricsTuning.excludeMetrics }} +{{- $labelSelectors := list }} +{{- range $label, $value := (index .Values "node-exporter").labelMatchers }} + {{- $labelSelectors = append $labelSelectors (printf "%s=%s" $label $value) }} +{{- end }} +{{- if (index .Values "node-exporter").deploy }} + {{- $labelSelectors = append $labelSelectors (printf "release=%s" .Release.Name) }} +{{- end }} + +// Node Exporter +discovery.kubernetes "node_exporter" { + role = "pod" + + selectors { + role = "pod" + label = {{ $labelSelectors | join "," | quote }} + } + +{{- if (index .Values "node-exporter").deploy }} + namespaces { + names = [{{ .Release.Namespace | quote }}] + } +{{- else if (index .Values "node-exporter").namespace }} + namespaces { + names = [{{ (index .Values "node-exporter").namespace | quote }}] + } +{{- end }} +} + +discovery.relabel "node_exporter" { + targets = discovery.kubernetes.node_exporter.targets + + // keep only the specified metrics port name, and pods that are Running and ready + rule { + source_labels = [ + "__meta_kubernetes_pod_container_port_name", + "__meta_kubernetes_pod_container_init", + "__meta_kubernetes_pod_phase", + "__meta_kubernetes_pod_ready", + ] + separator = "@" + regex = "{{ (index .Values "node-exporter").service.portName }}@false@Running@true" + action = "keep" + } + + // Set the instance label to the node name + rule { + source_labels = ["__meta_kubernetes_pod_node_name"] + action = "replace" + target_label = "instance" + } + + // set the namespace label + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + + // set the pod label + rule { + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + + // set the container label + rule { + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + + // set a workload label + rule { + source_labels = [ + "__meta_kubernetes_pod_controller_kind", + "__meta_kubernetes_pod_controller_name", + ] + separator = "/" + target_label = "workload" + } + // remove the hash from the ReplicaSet + rule { + source_labels = ["workload"] + regex = "(ReplicaSet/.+)-.+" + target_label = "workload" + } + + // set the app name if specified as metadata labels "app:" or "app.kubernetes.io/name:" or "k8s-app:" + rule { + action = "replace" + source_labels = [ + "__meta_kubernetes_pod_label_app_kubernetes_io_name", + "__meta_kubernetes_pod_label_k8s_app", + "__meta_kubernetes_pod_label_app", + ] + separator = ";" + regex = "^(?:;*)?([^;]+).*$" + replacement = "$1" + target_label = "app" + } + + // set the component if specified as metadata labels "component:" or "app.kubernetes.io/component:" or "k8s-component:" + rule { + action = "replace" + source_labels = [ + "__meta_kubernetes_pod_label_app_kubernetes_io_component", + "__meta_kubernetes_pod_label_k8s_component", + "__meta_kubernetes_pod_label_component", + ] + regex = "^(?:;*)?([^;]+).*$" + replacement = "$1" + target_label = "component" + } + + // set a source label + rule { + action = "replace" + replacement = "kubernetes" + target_label = "source" + } + +{{- if (index .Values "node-exporter").extraDiscoveryRules }} + {{ (index .Values "node-exporter").extraDiscoveryRules | nindent 2 }} +{{- end }} +} + +prometheus.scrape "node_exporter" { + targets = discovery.relabel.node_exporter.output + job_name = {{ (index .Values "node-exporter").jobLabel | quote }} + scrape_interval = {{ (index .Values "node-exporter").scrapeInterval | default .Values.global.scrapeInterval | quote }} + scheme = {{ (index .Values "node-exporter").service.scheme | quote }} + bearer_token_file = {{ (index .Values "node-exporter").bearerTokenFile | quote }} + tls_config { + insecure_skip_verify = true + } + + clustering { + enabled = true + } + +{{- if or $metricAllowList $metricDenyList (index .Values "node-exporter").metricsTuning.dropMetricsForFilesystem (index .Values "node-exporter").extraMetricProcessingRules }} + forward_to = [prometheus.relabel.node_exporter.receiver] +} + +prometheus.relabel "node_exporter" { + max_cache_size = {{ (index .Values "node-exporter").maxCacheSize | default .Values.global.maxCacheSize | int }} + +{{- if $metricAllowList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricAllowList | join "|" | quote }} + action = "keep" + } +{{- end }} +{{- if $metricDenyList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricDenyList | join "|" | quote }} + action = "drop" + } +{{- end }} +{{- if (index .Values "node-exporter").metricsTuning.dropMetricsForFilesystem }} + // Drop metrics for certain file systems + rule { + source_labels = ["__name__", "fstype"] + separator = "@" + regex = "node_filesystem.*@({{ join "|" (index .Values "node-exporter").metricsTuning.dropMetricsForFilesystem }})" + action = "drop" + } +{{- end }} + +{{- if (index .Values "node-exporter").extraMetricProcessingRules }} + {{ (index .Values "node-exporter").extraMetricProcessingRules | nindent 2}} +{{- end }} +{{- end }} + forward_to = argument.metrics_destinations.value +} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-cluster-metrics/templates/_notes.tpl b/grafana/charts/feature-cluster-metrics/templates/_notes.tpl new file mode 100644 index 0000000..c40f96e --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/templates/_notes.tpl @@ -0,0 +1,47 @@ +{{- define "feature.clusterMetrics.notes.deployments" }} +{{- if (index .Values "kube-state-metrics").deploy }} +* kube-state-metrics (Deployment) +{{- end }} +{{- if (index .Values "node-exporter").deploy }} +* Node Exporter (DaemonSet) +{{- end }} +{{- if (index .Values "windows-exporter").deploy }} +* Windows Exporter (DaemonSet) +{{- end }} +{{- if .Values.kepler.enabled }} +* Kepler (DaemonSet) +{{- end }} +{{- end }} + +{{- define "feature.clusterMetrics.notes.task" }} +Scrape Kubernetes Cluster metrics +{{- end }} + +{{- define "feature.clusterMetrics.notes.actions" }}{{- end }} + +{{- define "feature.clusterMetrics.summary" -}} +{{- $sources := list }} +{{- if .Values.controlPlane.enabled }}{{- $sources = append $sources "controlPlane" }}{{ end }} +{{- if .Values.kubelet.enabled }}{{- $sources = append $sources "kubelet" }}{{ end }} +{{- if .Values.kubeletResource.enabled }}{{- $sources = append $sources "kubeletResource" }}{{ end }} +{{- if .Values.cadvisor.enabled }}{{- $sources = append $sources "cadvisor" }}{{ end }} +{{- if .Values.apiServer.enabled }}{{- $sources = append $sources "apiServer" }}{{ end }} +{{- if .Values.kubeControllerManager.enabled }}{{- $sources = append $sources "kubeControllerManager" }}{{ end }} +{{- if .Values.kubeProxy.enabled }}{{- $sources = append $sources "kubeProxy" }}{{ end }} +{{- if .Values.kubeScheduler.enabled }}{{- $sources = append $sources "kubeScheduler" }}{{ end }} +{{- if (index .Values "kube-state-metrics").enabled }}{{- $sources = append $sources "kube-state-metrics" }}{{ end }} +{{- if (index .Values "node-exporter").enabled }}{{- $sources = append $sources "node-exporter" }}{{ end }} +{{- if (index .Values "windows-exporter").enabled }}{{- $sources = append $sources "windows-exporter" }}{{ end }} +{{- if .Values.kepler.enabled }}{{- $sources = append $sources "kepler" }}{{ end }} + +{{- $deployments := list }} +{{- if (index .Values "kube-state-metrics").deploy }}{{- $deployments = append $deployments "kube-state-metrics" }}{{ end }} +{{- if (index .Values "node-exporter").deploy }}{{- $deployments = append $deployments "node-exporter" }}{{ end }} +{{- if (index .Values "windows-exporter").deploy }}{{- $deployments = append $deployments "windows-exporter" }}{{ end }} +{{- if .Values.kepler.enabled }}{{- $deployments = append $deployments "kepler" }}{{ end }} +version: {{ .Chart.Version }} +sources: {{ $sources | join "," }} +{{- if ne (len $deployments) 0 }} +deployments: {{ $deployments | join "," }} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-cluster-metrics/templates/_opencost.alloy.tpl b/grafana/charts/feature-cluster-metrics/templates/_opencost.alloy.tpl new file mode 100644 index 0000000..7a3093e --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/templates/_opencost.alloy.tpl @@ -0,0 +1,79 @@ +{{ define "feature.clusterMetrics.opencost.allowList" }} +{{- $allowList := list }} +{{ if .Values.opencost.metricsTuning.useDefaultAllowList }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") (.Files.Get "default-allow-lists/opencost.yaml" | fromYamlArray) -}} +{{ end }} +{{ if .Values.opencost.metricsTuning.includeMetrics }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") .Values.opencost.metricsTuning.includeMetrics -}} +{{ end }} +{{ $allowList | uniq | toYaml }} +{{ end }} + +{{- define "feature.clusterMetrics.opencost.alloy" }} +{{- if .Values.opencost.enabled }} +{{- $metricAllowList := include "feature.clusterMetrics.opencost.allowList" . | fromYamlArray }} +{{- $metricDenyList := .Values.opencost.metricsTuning.excludeMetrics }} +{{- $labelSelectors := list }} +{{- range $k, $v := .Values.opencost.labelMatchers }} +{{- $labelSelectors = append $labelSelectors (printf "%s=%s" $k $v) }} +{{- end }} + +discovery.kubernetes "opencost" { + role = "pod" + namespaces { + own_namespace = true + } + selectors { + role = "pod" + label = {{ $labelSelectors | join "," | quote }} + } +} + +discovery.relabel "opencost" { + targets = discovery.kubernetes.opencost.targets + rule { + source_labels = ["__meta_kubernetes_pod_node_name"] + action = "replace" + target_label = "instance" + } +{{- if .Values.opencost.extraDiscoveryRules }} +{{ .Values.opencost.extraDiscoveryRules | indent 2 }} +{{- end }} +} + +prometheus.scrape "opencost" { + targets = discovery.relabel.opencost.output + job_name = {{ .Values.opencost.jobLabel | quote }} + honor_labels = true + scrape_interval = {{ .Values.opencost.scrapeInterval | default .Values.global.scrapeInterval | quote }} + clustering { + enabled = true + } +{{- if or $metricAllowList $metricDenyList .Values.opencost.extraMetricProcessingRules }} + forward_to = [prometheus.relabel.opencost.receiver] +} + +prometheus.relabel "opencost" { + max_cache_size = {{ .Values.opencost.maxCacheSize | default .Values.global.maxCacheSize | int }} +{{- if $metricAllowList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricAllowList | join "|" | quote }} + action = "keep" + } +{{- end }} +{{- if $metricDenyList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricDenyList | join "|" | quote }} + action = "drop" + } +{{- end }} +{{- if .Values.opencost.extraMetricProcessingRules }} +{{ .Values.opencost.extraMetricProcessingRules | indent 2 }} +{{- end }} +{{- end }} + forward_to = argument.metrics_destinations.value +} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-cluster-metrics/templates/_windows_exporter.alloy.tpl b/grafana/charts/feature-cluster-metrics/templates/_windows_exporter.alloy.tpl new file mode 100644 index 0000000..a8eaa2d --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/templates/_windows_exporter.alloy.tpl @@ -0,0 +1,90 @@ +{{- define "feature.clusterMetrics.windows_exporter.allowList" }} +{{- $allowList := list }} +{{ if (index .Values "windows-exporter").metricsTuning.useDefaultAllowList }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") (.Files.Get "default-allow-lists/windows-exporter.yaml" | fromYamlArray) -}} +{{ end }} +{{ if (index .Values "windows-exporter").metricsTuning.useIntegrationAllowList }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") (.Files.Get "default-allow-lists/windows-exporter-integration.yaml" | fromYamlArray) -}} +{{ end }} +{{ if (index .Values "windows-exporter").metricsTuning.includeMetrics }} +{{- $allowList = concat $allowList (list "up" "scrape_samples_scraped") (index .Values "windows-exporter").metricsTuning.includeMetrics -}} +{{ end }} +{{ $allowList | uniq | toYaml }} +{{- end }} + +{{- define "feature.clusterMetrics.windows_exporter.alloy" }} +{{- if (index .Values "windows-exporter").enabled }} +{{- $metricAllowList := include "feature.clusterMetrics.windows_exporter.allowList" . | fromYamlArray }} +{{- $metricDenyList := (index .Values "windows-exporter").metricsTuning.excludeMetrics }} +{{- $labelSelectors := list }} +{{- range $label, $value := (index .Values "windows-exporter").labelMatchers }} + {{- $labelSelectors = append $labelSelectors (printf "%s=%s" $label $value) }} +{{- end }} +{{- if (index .Values "windows-exporter").deploy }} + {{- $labelSelectors = append $labelSelectors (printf "release=%s" .Release.Name) }} +{{- end }} + +discovery.kubernetes "windows_exporter_pods" { + role = "pod" +{{- if (index .Values "windows-exporter").deploy }} + namespaces { + names = [{{ .Release.Namespace | quote }}] + } +{{- else if (index .Values "windows-exporter").namespace }} + namespaces { + names = [{{ (index .Values "windows-exporter").namespace | quote }}] + } +{{- end }} + selectors { + role = "pod" + label = {{ $labelSelectors | join "," | quote }} + } +} + +discovery.relabel "windows_exporter" { + targets = discovery.kubernetes.windows_exporter_pods.targets + rule { + source_labels = ["__meta_kubernetes_pod_node_name"] + action = "replace" + target_label = "instance" + } +{{- if (index .Values "windows-exporter").extraDiscoveryRules }} + {{ (index .Values "windows-exporter").extraDiscoveryRules | nindent 2 }} +{{- end }} +} + +prometheus.scrape "windows_exporter" { + job_name = {{ (index .Values "windows-exporter").jobLabel | quote }} + targets = discovery.relabel.windows_exporter.output + scrape_interval = {{ (index .Values "windows-exporter").scrapeInterval | default .Values.global.scrapeInterval | quote }} + clustering { + enabled = true + } +{{- if or $metricAllowList $metricDenyList (index .Values "windows-exporter").extraMetricProcessingRules }} + forward_to = [prometheus.relabel.windows_exporter.receiver] +} + +prometheus.relabel "windows_exporter" { + max_cache_size = {{ (index .Values "windows-exporter").maxCacheSize | default .Values.global.maxCacheSize | int }} +{{- if $metricAllowList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricAllowList | join "|" | quote }} + action = "keep" + } +{{- end }} +{{- if $metricDenyList }} + rule { + source_labels = ["__name__"] + regex = {{ $metricDenyList | join "|" | quote }} + action = "drop" + } +{{- end }} +{{- if (index .Values "windows-exporter").extraMetricProcessingRules }} +{{ (index .Values "windows-exporter").extraMetricProcessingRules | indent 2 }} +{{- end }} +{{- end }} + forward_to = argument.metrics_destinations.value +} +{{- end }} +{{- end }} diff --git a/grafana/charts/feature-cluster-metrics/templates/configmap.yaml b/grafana/charts/feature-cluster-metrics/templates/configmap.yaml new file mode 100644 index 0000000..2944698 --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/templates/configmap.yaml @@ -0,0 +1,13 @@ +{{- if .Values.deployAsConfigMap }} +{{- $alloyConfig := include "feature.clusterMetrics.module" . }} +{{- $alloyConfig = regexReplaceAll `[ \t]+(\r?\n)` $alloyConfig "\n" }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "feature.clusterMetrics.fullname" . }} + namespace: {{ .Release.Namespace }} +data: + module.alloy: |- + {{- $alloyConfig | trim | nindent 4 }} +{{- end }} diff --git a/grafana/charts/feature-cluster-metrics/templates/platform_specific/openshift/kepler-scc.yaml b/grafana/charts/feature-cluster-metrics/templates/platform_specific/openshift/kepler-scc.yaml new file mode 100644 index 0000000..1b2f216 --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/templates/platform_specific/openshift/kepler-scc.yaml @@ -0,0 +1,66 @@ +{{- if and (eq .Values.global.platform "openshift") .Values.kepler.enabled }} +--- +apiVersion: security.openshift.io/v1 +kind: SecurityContextConstraints +metadata: + name: {{ include "kepler.fullname" .Subcharts.kepler }} +allowHostDirVolumePlugin: true +allowHostIPC: false +allowHostNetwork: true +allowHostPID: false +allowHostPorts: true +allowPrivilegeEscalation: true +allowPrivilegedContainer: true +allowedCapabilities: [] +defaultAddCapabilities: null +defaultAllowPrivilegeEscalation: false +forbiddenSysctls: +- '*' +fsGroup: + type: RunAsAny +groups: [] +priority: null +readOnlyRootFilesystem: true +requiredDropCapabilities: null +runAsUser: + type: RunAsAny +seLinuxContext: + type: RunAsAny +seccompProfiles: + - runtime/default +supplementalGroups: + type: RunAsAny +users: + - system:serviceaccount:{{ .Release.Namespace }}:{{ include "kepler.fullname" .Subcharts.kepler }} +volumes: +- configMap +- hostPath +- projected +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "kepler.fullname" .Subcharts.kepler }}-scc +rules: +- verbs: + - use + apiGroups: + - security.openshift.io + resources: + - securitycontextconstraints + resourceNames: + - {{ include "kepler.fullname" .Subcharts.kepler }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "kepler.fullname" .Subcharts.kepler }}-scc +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "kepler.fullname" .Subcharts.kepler }}-scc +subjects: +- kind: ServiceAccount + name: {{ include "kepler.fullname" .Subcharts.kepler }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/grafana/charts/feature-cluster-metrics/tests/__snapshot__/.gitkeep b/grafana/charts/feature-cluster-metrics/tests/__snapshot__/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/grafana/charts/feature-cluster-metrics/tests/__snapshot__/alternative-discovery_test.yaml.snap b/grafana/charts/feature-cluster-metrics/tests/__snapshot__/alternative-discovery_test.yaml.snap new file mode 100644 index 0000000..a1e0ef6 --- /dev/null +++ b/grafana/charts/feature-cluster-metrics/tests/__snapshot__/alternative-discovery_test.yaml.snap @@ -0,0 +1,1077 @@ +should be able to find the Kubelet and cAdvisor via the API server proxy: + 1: | + |- + declare "cluster_metrics" { + argument "metrics_destinations" { + comment = "Must be a list of metric destinations where collected metrics should be forwarded to" + } + discovery.kubernetes "nodes" { + role = "node" + } + + // Kubelet + discovery.relabel "kubelet" { + targets = discovery.kubernetes.nodes.targets + rule { + target_label = "__address__" + replacement = "kubernetes.default.svc.cluster.local:443" + } + rule { + source_labels = ["__meta_kubernetes_node_name"] + regex = "(.+)" + replacement = "/api/v1/nodes/${1}/proxy/metrics" + target_label = "__metrics_path__" + } + // set the node label + rule { + source_labels = ["__meta_kubernetes_node_name"] + target_label = "node" + } + + // set the app name if specified as metadata labels "app:" or "app.kubernetes.io/name:" or "k8s-app:" + rule { + action = "replace" + source_labels = [ + "__meta_kubernetes_node_label_app_kubernetes_io_name", + "__meta_kubernetes_node_label_k8s_app", + "__meta_kubernetes_node_label_app", + ] + separator = ";" + regex = "^(?:;*)?([^;]+).*$" + replacement = "$1" + target_label = "app" + } + + // set a source label + rule { + action = "replace" + replacement = "kubernetes" + target_label = "source" + } + } + + prometheus.scrape "kubelet" { + targets = discovery.relabel.kubelet.output + job_name = "integrations/kubernetes/kubelet" + scheme = "https" + scrape_interval = "60s" + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + + tls_config { + ca_file = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" + insecure_skip_verify = true + server_name = "kubernetes" + } + + clustering { + enabled = true + } + + forward_to = [prometheus.relabel.kubelet.receiver] + } + + prometheus.relabel "kubelet" { + max_cache_size = 100000 + rule { + source_labels = ["__name__"] + regex = "up|scrape_samples_scraped|go_goroutines|kubelet_certificate_manager_client_expiration_renew_errors|kubelet_certificate_manager_client_ttl_seconds|kubelet_certificate_manager_server_ttl_seconds|kubelet_cgroup_manager_duration_seconds_bucket|kubelet_cgroup_manager_duration_seconds_count|kubelet_node_config_error|kubelet_node_name|kubelet_pleg_relist_duration_seconds_bucket|kubelet_pleg_relist_duration_seconds_count|kubelet_pleg_relist_interval_seconds_bucket|kubelet_pod_start_duration_seconds_bucket|kubelet_pod_start_duration_seconds_count|kubelet_pod_worker_duration_seconds_bucket|kubelet_pod_worker_duration_seconds_count|kubelet_running_container_count|kubelet_running_containers|kubelet_running_pod_count|kubelet_running_pods|kubelet_runtime_operations_errors_total|kubelet_runtime_operations_total|kubelet_server_expiration_renew_errors|kubelet_volume_stats_available_bytes|kubelet_volume_stats_capacity_bytes|kubelet_volume_stats_inodes|kubelet_volume_stats_inodes_free|kubelet_volume_stats_inodes_used|kubelet_volume_stats_used_bytes|kubernetes_build_info|namespace_workload_pod|process_cpu_seconds_total|process_resident_memory_bytes|rest_client_requests_total|storage_operation_duration_seconds_count|storage_operation_errors_total|volume_manager_total_volumes" + action = "keep" + } + + forward_to = argument.metrics_destinations.value + } + + // Kubelet Resources + discovery.relabel "kubelet_resources" { + targets = discovery.kubernetes.nodes.targets + rule { + target_label = "__address__" + replacement = "kubernetes.default.svc.cluster.local:443" + } + rule { + source_labels = ["__meta_kubernetes_node_name"] + regex = "(.+)" + replacement = "/api/v1/nodes/${1}/proxy/metrics/resource" + target_label = "__metrics_path__" + } + + // set the node label + rule { + source_labels = ["__meta_kubernetes_node_name"] + target_label = "node" + } + + // set the app name if specified as metadata labels "app:" or "app.kubernetes.io/name:" or "k8s-app:" + rule { + action = "replace" + source_labels = [ + "__meta_kubernetes_node_label_app_kubernetes_io_name", + "__meta_kubernetes_node_label_k8s_app", + "__meta_kubernetes_node_label_app", + ] + separator = ";" + regex = "^(?:;*)?([^;]+).*$" + replacement = "$1" + target_label = "app" + } + + // set a source label + rule { + action = "replace" + replacement = "kubernetes" + target_label = "source" + } + } + + prometheus.scrape "kubelet_resources" { + targets = discovery.relabel.kubelet_resources.output + job_name = "integrations/kubernetes/resources" + scheme = "https" + scrape_interval = "60s" + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + + tls_config { + ca_file = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" + insecure_skip_verify = true + server_name = "kubernetes" + } + + clustering { + enabled = true + } + + forward_to = [prometheus.relabel.kubelet_resources.receiver] + } + + prometheus.relabel "kubelet_resources" { + max_cache_size = 100000 + rule { + source_labels = ["__name__"] + regex = "up|scrape_samples_scraped|node_cpu_usage_seconds_total|node_memory_working_set_bytes" + action = "keep" + } + + forward_to = argument.metrics_destinations.value + } + + // Kubelet Probes + discovery.relabel "kubelet_probes" { + targets = discovery.kubernetes.nodes.targets + rule { + target_label = "__address__" + replacement = "kubernetes.default.svc.cluster.local:443" + } + rule { + source_labels = ["__meta_kubernetes_node_name"] + regex = "(.+)" + replacement = "/api/v1/nodes/${1}/proxy/metrics/probes" + target_label = "__metrics_path__" + } + + // set the node label + rule { + source_labels = ["__meta_kubernetes_node_name"] + target_label = "node" + } + + // set the app name if specified as metadata labels "app:" or "app.kubernetes.io/name:" or "k8s-app:" + rule { + action = "replace" + source_labels = [ + "__meta_kubernetes_node_label_app_kubernetes_io_name", + "__meta_kubernetes_node_label_k8s_app", + "__meta_kubernetes_node_label_app", + ] + separator = ";" + regex = "^(?:;*)?([^;]+).*$" + replacement = "$1" + target_label = "app" + } + + // set a source label + rule { + action = "replace" + replacement = "kubernetes" + target_label = "source" + } + } + + prometheus.scrape "kubelet_probes" { + targets = discovery.relabel.kubelet_probes.output + job_name = "integrations/kubernetes/probes" + scheme = "https" + scrape_interval = "60s" + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + + tls_config { + ca_file = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" + insecure_skip_verify = true + server_name = "kubernetes" + } + + clustering { + enabled = true + } + + forward_to = [prometheus.relabel.kubelet_probes.receiver] + } + + prometheus.relabel "kubelet_probes" { + max_cache_size = 100000 + rule { + source_labels = ["__name__"] + regex = "up|scrape_samples_scraped|prober_.*" + action = "keep" + } + + forward_to = argument.metrics_destinations.value + } + + // cAdvisor + discovery.relabel "cadvisor" { + targets = discovery.kubernetes.nodes.targets + rule { + target_label = "__address__" + replacement = "kubernetes.default.svc.cluster.local:443" + } + rule { + source_labels = ["__meta_kubernetes_node_name"] + regex = "(.+)" + replacement = "/api/v1/nodes/${1}/proxy/metrics/cadvisor" + target_label = "__metrics_path__" + } + + rule { + source_labels = ["__meta_kubernetes_node_name"] + target_label = "node" + } + // set the app name if specified as metadata labels "app:" or "app.kubernetes.io/name:" or "k8s-app:" + rule { + action = "replace" + source_labels = [ + "__meta_kubernetes_node_label_app_kubernetes_io_name", + "__meta_kubernetes_node_label_k8s_app", + "__meta_kubernetes_node_label_app", + ] + separator = ";" + regex = "^(?:;*)?([^;]+).*$" + replacement = "$1" + target_label = "app" + } + + // set a source label + rule { + action = "replace" + replacement = "kubernetes" + target_label = "source" + } + } + + prometheus.scrape "cadvisor" { + targets = discovery.relabel.cadvisor.output + job_name = "integrations/kubernetes/cadvisor" + scheme = "https" + scrape_interval = "60s" + bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token" + + tls_config { + ca_file = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" + insecure_skip_verify = true + server_name = "kubernetes" + } + + clustering { + enabled = true + } + + forward_to = [prometheus.relabel.cadvisor.receiver] + } + + prometheus.relabel "cadvisor" { + max_cache_size = 100000 + rule { + source_labels = ["__name__"] + regex = "up|scrape_samples_scraped|container_cpu_cfs_periods_total|container_cpu_cfs_throttled_periods_total|container_cpu_usage_seconds_total|container_fs_reads_bytes_total|container_fs_reads_total|container_fs_writes_bytes_total|container_fs_writes_total|container_memory_cache|container_memory_rss|container_memory_swap|container_memory_working_set_bytes|container_network_receive_bytes_total|container_network_receive_packets_dropped_total|container_network_receive_packets_total|container_network_transmit_bytes_total|container_network_transmit_packets_dropped_total|container_network_transmit_packets_total|machine_memory_bytes" + action = "keep" + } + // Drop empty container labels, addressing https://github.com/google/cadvisor/issues/2688 + rule { + source_labels = ["__name__","container"] + separator = "@" + regex = "(container_cpu_.*|container_fs_.*|container_memory_.*)@" + action = "drop" + } + // Drop empty image labels, addressing https://github.com/google/cadvisor/issues/2688 + rule { + source_labels = ["__name__","image"] + separator = "@" + regex = "(container_cpu_.*|container_fs_.*|container_memory_.*|container_network_.*)@" + action = "drop" + } + // Normalizing unimportant labels (not deleting to continue satisfying